Merge changes from v6 branch
- Add workspaces (gated behind configuration) - Switch from handlers to providers for DI - Fix for #597
This commit is contained in:
Коммит
bee3a2f378
|
@ -7,8 +7,8 @@ internal static class Program
|
|||
{
|
||||
var builder = DistributedApplication.CreateBuilder(args);
|
||||
|
||||
//builder.AddProject<extractor>("extractor");
|
||||
builder.AddProject<integration_tests>("integration-tests");
|
||||
//.WithEnvironment("CSCHECK_SEED", "0000KOIPe036");
|
||||
|
||||
builder.Build().Run();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
|
@ -9,11 +9,13 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.0.1" />
|
||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\extractor\extractor.csproj" />
|
||||
<ProjectReference Include="..\integration.tests\integration.tests.csproj" />
|
||||
<ProjectReference Include="..\publisher\publisher.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -8,23 +8,26 @@ using System.Collections.Generic;
|
|||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace common.tests;
|
||||
|
||||
public static class Generator
|
||||
{
|
||||
public static Gen<Internet> Internet { get; } = Gen.Const(new Internet());
|
||||
public static Gen<Internet> Internet { get; } =
|
||||
new GenBogusDataSet<Internet>(() => new Internet());
|
||||
|
||||
public static Gen<Address> Address { get; } = Gen.Const(new Address());
|
||||
public static Gen<Address> Address { get; } =
|
||||
new GenBogusDataSet<Address>(() => new Address());
|
||||
|
||||
public static Gen<Lorem> Lorem { get; } = Gen.Const(new Lorem());
|
||||
public static Gen<Lorem> Lorem { get; } =
|
||||
new GenBogusDataSet<Lorem>(() => new Lorem());
|
||||
|
||||
public static Gen<Uri> AbsoluteUri { get; } =
|
||||
from internet in Internet
|
||||
select new Uri(internet.Url());
|
||||
|
||||
public static Gen<Bogus.DataSets.System> BogusSystem { get; } = Gen.Const(new Bogus.DataSets.System());
|
||||
public static Gen<Bogus.DataSets.System> BogusSystem { get; } =
|
||||
new GenBogusDataSet<Bogus.DataSets.System>(() => new Bogus.DataSets.System());
|
||||
|
||||
public static Gen<DirectoryInfo> DirectoryInfo { get; } =
|
||||
from system in BogusSystem
|
||||
|
@ -34,73 +37,34 @@ public static class Generator
|
|||
from system in BogusSystem
|
||||
select new FileInfo(system.FilePath());
|
||||
|
||||
public static Gen<string> FileName { get; } =
|
||||
from system in BogusSystem
|
||||
select system.FileName();
|
||||
|
||||
public static Gen<string> NonEmptyString { get; } =
|
||||
Gen.String.Where(x => string.IsNullOrWhiteSpace(x) is false);
|
||||
|
||||
public static Gen<JsonValue> JsonValue { get; } = GenerateJsonValue();
|
||||
|
||||
public static Gen<JsonObject> JsonObject { get; } = GenerateJsonObject();
|
||||
|
||||
public static Gen<JsonArray> JsonArray { get; } = GenerateJsonArray();
|
||||
|
||||
public static Gen<JsonNode> JsonNode { get; } = GenerateJsonNode();
|
||||
|
||||
private static Gen<JsonValue> GenerateJsonValue() =>
|
||||
Gen.OneOf(Gen.Bool.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Byte.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Char.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.DateTime.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.DateTimeOffset.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Decimal.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Double.Where(double.IsFinite).Where(x => double.IsNaN(x) is false).Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Float.Where(float.IsFinite).Where(x => float.IsNaN(x) is false).Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Guid.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Int.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Long.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.SByte.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.Short.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.String.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.UInt.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.ULong.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)),
|
||||
Gen.UShort.Select(x => System.Text.Json.Nodes.JsonValue.Create(x)));
|
||||
|
||||
private static Gen<JsonObject> GenerateJsonObject() =>
|
||||
GenerateJsonObject(GenerateJsonNode(), limits: 100);
|
||||
|
||||
private static Gen<JsonObject> GenerateJsonObject(Gen<JsonNode> nodeGen, uint limits) =>
|
||||
Gen.Dictionary(Gen.String.AlphaNumeric,
|
||||
nodeGen.Null())[0, (int)limits]
|
||||
.Select(x => new JsonObject(x));
|
||||
|
||||
private static Gen<JsonArray> GenerateJsonArray() =>
|
||||
GenerateJsonArray(GenerateJsonNode(), limits: 100);
|
||||
|
||||
private static Gen<JsonArray> GenerateJsonArray(Gen<JsonNode> nodeGen, uint limits) =>
|
||||
nodeGen.Null()
|
||||
.Array[0, (int)limits]
|
||||
.Select(x => new JsonArray(x));
|
||||
|
||||
private static Gen<JsonNode> GenerateJsonNode() =>
|
||||
Gen.Recursive<JsonNode>((depth, gen) =>
|
||||
depth == 3
|
||||
? GenerateJsonValue().Select(x => x as JsonNode)
|
||||
: Gen.OneOf(GenerateJsonValue().Select(x => x as JsonNode),
|
||||
GenerateJsonObject(gen, limits: (uint)depth).Select(x => x as JsonNode),
|
||||
GenerateJsonArray(gen, limits: (uint)depth).Select(x => x as JsonNode)));
|
||||
public static Gen<string> AlphaNumericStringBetween(int minimumLength, int maximumLength) =>
|
||||
Gen.Char
|
||||
.AlphaNumeric
|
||||
.Array[minimumLength, maximumLength]
|
||||
.Select(x => new string(x));
|
||||
|
||||
public static Gen<string> AlphaNumericStringWithLength(int length) =>
|
||||
Gen.Char.AlphaNumeric.Array[length].Select(x => new string(x));
|
||||
|
||||
public static Gen<string> AlphaNumericStringBetween(int minimumLength, int maximumLength) =>
|
||||
Gen.Char.AlphaNumeric.Array[minimumLength, maximumLength].Select(x => new string(x));
|
||||
Gen.Char
|
||||
.AlphaNumeric
|
||||
.Array[length]
|
||||
.Select(x => new string(x));
|
||||
|
||||
public static Gen<ImmutableArray<T>> ImmutableArrayOf<T>(this Gen<T> gen) =>
|
||||
gen.List.Select(x => x.ToImmutableArray());
|
||||
gen.List
|
||||
.Select(x => x.ToImmutableArray());
|
||||
|
||||
public static Gen<ImmutableArray<T>> ImmutableArrayOf<T>(this Gen<T> gen, int minimumCount, int maximumCount) =>
|
||||
gen.List[minimumCount, maximumCount].Select(x => x.ToImmutableArray());
|
||||
gen.List[minimumCount, maximumCount]
|
||||
.Select(x => x.ToImmutableArray());
|
||||
|
||||
public static Gen<ImmutableArray<T>> SubImmutableArrayOf<T>(IEnumerable<T> enumerable)
|
||||
public static Gen<ImmutableArray<T>> SubImmutableArrayOf<T>(ICollection<T> enumerable)
|
||||
{
|
||||
var array = enumerable.ToArray();
|
||||
|
||||
|
@ -108,84 +72,54 @@ public static class Generator
|
|||
select items.ToImmutableArray();
|
||||
}
|
||||
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T>(this Gen<T> gen) =>
|
||||
gen.List.Select(x => x.ToFrozenSet());
|
||||
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T>(this Gen<T> gen, int minimumCount, int maximumCount)
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T, TKey>(this Gen<T> gen, Func<T, TKey> keySelector, int minimumCount, int maximumCount)
|
||||
{
|
||||
if (maximumCount < minimumCount)
|
||||
{
|
||||
throw new ArgumentException("Maximum count must be greater than or equal to minimum count.", nameof(maximumCount));
|
||||
}
|
||||
var comparer = EqualityComparerBuilder.For<T>().EquateBy(keySelector);
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(minimumCount, nameof(minimumCount));
|
||||
|
||||
return gen.List[minimumCount, maximumCount].Select(x => x.ToFrozenSet());
|
||||
}
|
||||
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T>(this Gen<T> gen, IEqualityComparer<T> comparer) =>
|
||||
gen.List.Select(x => x.ToFrozenSet(comparer));
|
||||
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T>(this Gen<T> gen, IEqualityComparer<T> comparer, int minimumCount, int maximumCount)
|
||||
{
|
||||
if (maximumCount < minimumCount)
|
||||
{
|
||||
throw new ArgumentException("Maximum count must be greater than or equal to minimum count.", nameof(maximumCount));
|
||||
}
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(minimumCount, nameof(minimumCount));
|
||||
|
||||
return gen.List[minimumCount, maximumCount].Select(x => x.ToFrozenSet(comparer));
|
||||
return gen.FrozenSetOf(minimumCount, maximumCount, comparer);
|
||||
}
|
||||
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T, TKey>(this Gen<T> gen, Func<T, TKey> keySelector)
|
||||
{
|
||||
var comparer = EqualityComparerBuilder.For<T>().EquateBy(keySelector);
|
||||
|
||||
return gen.FrozenSetOf(comparer);
|
||||
return gen.List
|
||||
.Select(x => x.ToFrozenSet(comparer));
|
||||
}
|
||||
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T, TKey>(this Gen<T> gen, Func<T, TKey> keySelector, int minimumCount, int maximumCount)
|
||||
{
|
||||
var comparer = EqualityComparerBuilder.For<T>().EquateBy(keySelector);
|
||||
|
||||
return gen.FrozenSetOf(comparer, minimumCount, maximumCount);
|
||||
}
|
||||
|
||||
public static Gen<FrozenSet<T>> SubFrozenSetOf<T>(IEnumerable<T> enumerable) =>
|
||||
SubImmutableArrayOf(enumerable)
|
||||
.Select(x => x.ToFrozenSet());
|
||||
|
||||
public static Gen<FrozenSet<T>> SubFrozenSetOf<T>(IEnumerable<T> enumerable, IEqualityComparer<T> comparer) =>
|
||||
SubImmutableArrayOf(enumerable)
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T>(this Gen<T> gen, IEqualityComparer<T>? comparer = default) =>
|
||||
gen.List
|
||||
.Select(x => x.ToFrozenSet(comparer));
|
||||
|
||||
public static Gen<FrozenSet<T>> SubFrozenSetOf<T, TKey>(IEnumerable<T> enumerable, Func<T, TKey> keySelector)
|
||||
{
|
||||
var comparer = EqualityComparerBuilder.For<T>().EquateBy(keySelector);
|
||||
public static Gen<FrozenSet<T>> FrozenSetOf<T>(this Gen<T> gen, int minimumCount, int maximumCount, IEqualityComparer<T>? comparer = default) =>
|
||||
gen.List[minimumCount, maximumCount]
|
||||
.Select(x => x.ToFrozenSet(comparer));
|
||||
|
||||
return SubFrozenSetOf(enumerable, comparer);
|
||||
public static Gen<FrozenSet<T>> SubFrozenSetOf<T>(ICollection<T> enumerable, IEqualityComparer<T>? comparer = default)
|
||||
{
|
||||
var comparerToUse = comparer switch
|
||||
{
|
||||
null => enumerable switch
|
||||
{
|
||||
FrozenSet<T> frozenSet => frozenSet.Comparer,
|
||||
_ => comparer
|
||||
},
|
||||
_ => comparer
|
||||
};
|
||||
|
||||
return SubImmutableArrayOf(enumerable)
|
||||
.Select(x => x.ToFrozenSet(comparerToUse));
|
||||
}
|
||||
|
||||
public static Gen<FrozenSet<T>> DistinctBy<T, TKey>(this Gen<FrozenSet<T>> gen, Func<T, TKey> keySelector) =>
|
||||
from set in gen
|
||||
select set.DistinctBy(keySelector)
|
||||
.ToFrozenSet(set.Comparer);
|
||||
|
||||
public static Gen<Option<T>> OptionOf<T>(this Gen<T> gen) =>
|
||||
Gen.Frequency((1, Gen.Const(Option<T>.None)),
|
||||
(4, gen.Select(Option<T>.Some)));
|
||||
|
||||
public static Gen<string> ToUpperInvariant(this GenString gen) =>
|
||||
gen.Select(x => x.ToUpperInvariant());
|
||||
|
||||
public static Gen<Option<T>> Sequence<T>(this Option<Gen<T>> option) =>
|
||||
option.Match(gen => gen.Select(Option<T>.Some),
|
||||
() => Gen.Const(Option<T>.None));
|
||||
|
||||
public static Gen<FrozenSet<T>> SequenceToFrozenSet<T, TKey>(this IEnumerable<Gen<T>> gens, Func<T, TKey> keySelector) =>
|
||||
gens.SequenceToImmutableArray()
|
||||
.Select(x => x.ToFrozenSet(keySelector));
|
||||
|
||||
public static Gen<FrozenSet<T>> SequenceToFrozenSet<T>(this IEnumerable<Gen<T>> gens, IEqualityComparer<T>? comparer = null) =>
|
||||
gens.SequenceToImmutableArray()
|
||||
.Select(x => x.ToFrozenSet(comparer));
|
||||
|
||||
/// <summary>
|
||||
/// Converts a list of generators to a generator of lists
|
||||
/// </summary>
|
||||
|
@ -195,4 +129,95 @@ public static class Generator
|
|||
from t in gen
|
||||
select list.Add(t))
|
||||
select list.ToImmutableArray();
|
||||
|
||||
/// <summary>
|
||||
/// Converts a list of generators to a generator of frozen sets
|
||||
/// </summary>
|
||||
public static Gen<FrozenSet<T>> SequenceToFrozenSet<T, TKey>(this IEnumerable<Gen<T>> gens, Func<T, TKey> keySelector) =>
|
||||
gens.SequenceToImmutableArray()
|
||||
.Select(x => x.ToFrozenSet(keySelector));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a list of generators to a generator of frozen sets
|
||||
/// </summary>
|
||||
public static Gen<FrozenSet<T>> SequenceToFrozenSet<T>(this IEnumerable<Gen<T>> gens, IEqualityComparer<T>? comparer = null) =>
|
||||
gens.SequenceToImmutableArray()
|
||||
.Select(x => x.ToFrozenSet(comparer));
|
||||
|
||||
public static Gen<FrozenSet<T>> GenerateNewSet<T>(FrozenSet<T> original, Gen<FrozenSet<T>> newGen, Func<T, Gen<T>> updateGen) =>
|
||||
GenerateNewSet(original, newGen, updateGen, ChangeParameters.All);
|
||||
|
||||
private static Gen<FrozenSet<T>> GenerateNewSet<T>(FrozenSet<T> original, Gen<FrozenSet<T>> newGen, Func<T, Gen<T>> updateGen, ChangeParameters changeParameters)
|
||||
{
|
||||
var generator = from originalItems in Gen.Const(original)
|
||||
from itemsRemoved in changeParameters.Remove ? RemoveItems(originalItems) : Gen.Const(originalItems)
|
||||
from itemsAdded in changeParameters.Add ? AddItems(itemsRemoved, newGen) : Gen.Const(itemsRemoved)
|
||||
from itemsModified in changeParameters.Modify ? ModifyItems(itemsAdded, updateGen) : Gen.Const(itemsAdded)
|
||||
select itemsModified;
|
||||
|
||||
return changeParameters.MaxSize.Map(maxSize => generator.SelectMany(set => set.Count <= maxSize
|
||||
? generator
|
||||
: from smallerSet in Gen.Shuffle(set.ToArray(), maxSize)
|
||||
|
||||
select smallerSet.ToFrozenSet(set.Comparer)))
|
||||
.IfNone(generator);
|
||||
}
|
||||
|
||||
private static Gen<FrozenSet<T>> RemoveItems<T>(FrozenSet<T> set) =>
|
||||
from itemsToRemove in Generator.SubFrozenSetOf(set)
|
||||
select set.Except(itemsToRemove, set.Comparer)
|
||||
.ToFrozenSet(set.Comparer);
|
||||
|
||||
private static Gen<FrozenSet<T>> AddItems<T>(FrozenSet<T> set, Gen<FrozenSet<T>> gen) =>
|
||||
from itemsToAdd in gen
|
||||
select set.Concat(itemsToAdd)
|
||||
.ToFrozenSet(set.Comparer);
|
||||
|
||||
private static Gen<FrozenSet<T>> ModifyItems<T>(FrozenSet<T> set, Func<T, Gen<T>> updateGen) =>
|
||||
from itemsToModify in Generator.SubFrozenSetOf(set)
|
||||
from modifiedItems in itemsToModify.Select(updateGen).SequenceToImmutableArray()
|
||||
select set.Concat(itemsToModify)
|
||||
.Concat(modifiedItems)
|
||||
.ToFrozenSet(set.Comparer);
|
||||
|
||||
private sealed record ChangeParameters
|
||||
{
|
||||
public required bool Add { get; init; }
|
||||
public required bool Modify { get; init; }
|
||||
public required bool Remove { get; init; }
|
||||
|
||||
public static ChangeParameters None { get; } = new()
|
||||
{
|
||||
Add = false,
|
||||
Modify = false,
|
||||
Remove = false
|
||||
};
|
||||
|
||||
public static ChangeParameters All { get; } = new()
|
||||
{
|
||||
Add = true,
|
||||
Modify = true,
|
||||
Remove = true
|
||||
};
|
||||
|
||||
public Option<int> MaxSize { get; init; } = Option<int>.None;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generator for Bogus dataset <typeparamref name="T"/>. It's set to a constant value,
|
||||
/// and its randomizer is seeded with the <see cref="Gen"/> seed.
|
||||
/// </summary>
|
||||
file sealed class GenBogusDataSet<T>(Func<T> creator) : Gen<T> where T : Bogus.DataSet
|
||||
{
|
||||
public override T Generate(PCG pcg, Size? min, out Size size)
|
||||
{
|
||||
var t = creator();
|
||||
t.Random = new Bogus.Randomizer((int)pcg.Seed);
|
||||
|
||||
size = new Size(0);
|
||||
|
||||
return t;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using CsCheck;
|
||||
using LanguageExt;
|
||||
using Nito.Comparers;
|
||||
using System.Collections.Frozen;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -35,8 +34,6 @@ public sealed record GroupModel
|
|||
select lorem.Paragraph();
|
||||
|
||||
public static Gen<FrozenSet<GroupModel>> GenerateSet() =>
|
||||
Generate().FrozenSetOf(EqualityComparerBuilder.For<GroupModel>()
|
||||
.EquateBy(x => x.Name)
|
||||
.ThenEquateBy(x => x.DisplayName),
|
||||
0, 10);
|
||||
Generate().FrozenSetOf(x => x.Name, 0, 10)
|
||||
.DistinctBy(x => x.DisplayName);
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using CsCheck;
|
||||
using LanguageExt;
|
||||
using Nito.Comparers;
|
||||
using System.Collections.Frozen;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -60,8 +59,6 @@ public sealed record ProductModel
|
|||
select lorem.Paragraph();
|
||||
|
||||
public static Gen<FrozenSet<ProductModel>> GenerateSet() =>
|
||||
Generate().FrozenSetOf(EqualityComparerBuilder.For<ProductModel>()
|
||||
.EquateBy(x => x.Name)
|
||||
.ThenEquateBy(x => x.DisplayName),
|
||||
0, 10);
|
||||
Generate().FrozenSetOf(x => x.Name, 0, 10)
|
||||
.DistinctBy(x => x.DisplayName);
|
||||
}
|
|
@ -3,6 +3,7 @@ using LanguageExt;
|
|||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace common.tests;
|
||||
|
@ -67,13 +68,13 @@ public record ServiceModel
|
|||
public static Gen<FrozenSet<ApiModel>> UpdateApis(FrozenSet<ApiModel> apis,
|
||||
ICollection<VersionSetModel> versionSets,
|
||||
ICollection<TagModel> tags) =>
|
||||
apis.Map(api => from version in UpdateApiVersion(versionSets)
|
||||
from revisions in UpdateApiRevisions(api.Revisions, tags)
|
||||
select api with
|
||||
{
|
||||
Version = version,
|
||||
Revisions = revisions
|
||||
})
|
||||
apis.Select(api => from version in UpdateApiVersion(versionSets)
|
||||
from revisions in UpdateApiRevisions(api.Revisions, tags)
|
||||
select api with
|
||||
{
|
||||
Version = version,
|
||||
Revisions = revisions
|
||||
})
|
||||
.SequenceToFrozenSet(apis.Comparer);
|
||||
|
||||
|
||||
|
@ -92,11 +93,11 @@ public record ServiceModel
|
|||
}
|
||||
|
||||
private static Gen<FrozenSet<ApiRevision>> UpdateApiRevisions(FrozenSet<ApiRevision> revisions, ICollection<TagModel> tags) =>
|
||||
revisions.Map(revision => from tags in UpdateApiTags(revision.Tags, tags)
|
||||
select revision with
|
||||
{
|
||||
Tags = tags
|
||||
})
|
||||
revisions.Select(revision => from tags in UpdateApiTags(revision.Tags, tags)
|
||||
select revision with
|
||||
{
|
||||
Tags = tags
|
||||
})
|
||||
.SequenceToFrozenSet(revisions.Comparer);
|
||||
|
||||
private static Gen<FrozenSet<ApiTagModel>> UpdateApiTags(FrozenSet<ApiTagModel> apiTags, ICollection<TagModel> tags)
|
||||
|
@ -107,7 +108,8 @@ public record ServiceModel
|
|||
.ToFrozenSet(apiTags.Comparer));
|
||||
}
|
||||
|
||||
var tagNames = tags.Select(tag => tag.Name);
|
||||
var tagNames = tags.Select(tag => tag.Name)
|
||||
.ToImmutableArray();
|
||||
|
||||
return from apiTagNames in Generator.SubImmutableArrayOf(tagNames)
|
||||
select apiTagNames.Select(tagName => new ApiTagModel { Name = tagName })
|
||||
|
@ -125,13 +127,13 @@ public record ServiceModel
|
|||
|
||||
var loggersArray = loggers.ToArray();
|
||||
|
||||
return from updates in diagnostics.Map(diagnostic => from logger in Gen.OneOfConst(loggersArray)
|
||||
select diagnostic with
|
||||
{
|
||||
// Diagnostic name must be "azuremonitor" if the logger type is AzureMonitor
|
||||
Name = logger.Type is LoggerType.AzureMonitor ? DiagnosticName.From("azuremonitor") : diagnostic.Name,
|
||||
LoggerName = logger.Name
|
||||
})
|
||||
return from updates in diagnostics.Select(diagnostic => from logger in Gen.OneOfConst(loggersArray)
|
||||
select diagnostic with
|
||||
{
|
||||
// Diagnostic name must be "azuremonitor" if the logger type is AzureMonitor
|
||||
Name = logger.Type is LoggerType.AzureMonitor ? DiagnosticName.From("azuremonitor") : diagnostic.Name,
|
||||
LoggerName = logger.Name
|
||||
})
|
||||
.SequenceToFrozenSet(diagnostics.Comparer)
|
||||
select updates;
|
||||
}
|
||||
|
@ -153,11 +155,11 @@ public record ServiceModel
|
|||
|
||||
var productsArray = products.ToArray();
|
||||
|
||||
return from updates in subscriptions.Map(subscription => from product in Gen.OneOfConst(productsArray)
|
||||
select subscription with
|
||||
{
|
||||
Scope = new SubscriptionScope.Product { Name = product.Name }
|
||||
})
|
||||
return from updates in subscriptions.Select(subscription => from product in Gen.OneOfConst(productsArray)
|
||||
select subscription with
|
||||
{
|
||||
Scope = new SubscriptionScope.Product { Name = product.Name }
|
||||
})
|
||||
.SequenceToFrozenSet(subscriptions.Comparer)
|
||||
select updates;
|
||||
}
|
||||
|
@ -172,11 +174,11 @@ public record ServiceModel
|
|||
|
||||
var apisArray = apis.ToArray();
|
||||
|
||||
return from updates in subscriptions.Map(subscription => from api in Gen.OneOfConst(apisArray)
|
||||
select subscription with
|
||||
{
|
||||
Scope = new SubscriptionScope.Api { Name = api.Name }
|
||||
})
|
||||
return from updates in subscriptions.Select(subscription => from api in Gen.OneOfConst(apisArray)
|
||||
select subscription with
|
||||
{
|
||||
Scope = new SubscriptionScope.Api { Name = api.Name }
|
||||
})
|
||||
.SequenceToFrozenSet(subscriptions.Comparer)
|
||||
select updates;
|
||||
}
|
||||
|
@ -185,15 +187,15 @@ public record ServiceModel
|
|||
ICollection<GroupModel> groups,
|
||||
ICollection<TagModel> tags,
|
||||
ICollection<ApiModel> apis) =>
|
||||
products.Map(product => from productGroups in UpdateProductGroups(product.Groups, groups)
|
||||
from productTags in UpdateProductTags(product.Tags, tags)
|
||||
from productApis in UpdateProductApis(product.Apis, apis)
|
||||
select product with
|
||||
{
|
||||
Groups = productGroups,
|
||||
Tags = productTags,
|
||||
Apis = productApis
|
||||
})
|
||||
products.Select(product => from productGroups in UpdateProductGroups(product.Groups, groups)
|
||||
from productTags in UpdateProductTags(product.Tags, tags)
|
||||
from productApis in UpdateProductApis(product.Apis, apis)
|
||||
select product with
|
||||
{
|
||||
Groups = productGroups,
|
||||
Tags = productTags,
|
||||
Apis = productApis
|
||||
})
|
||||
.SequenceToFrozenSet(products.Comparer);
|
||||
|
||||
private static Gen<FrozenSet<ProductGroupModel>> UpdateProductGroups(FrozenSet<ProductGroupModel> productGroups, ICollection<GroupModel> groups)
|
||||
|
@ -206,8 +208,8 @@ public record ServiceModel
|
|||
|
||||
var groupNames = groups.Select(group => group.Name).ToArray();
|
||||
|
||||
return productGroups.Map(productGroup => from groupName in Gen.OneOfConst(groupNames)
|
||||
select productGroup with { Name = groupName })
|
||||
return productGroups.Select(productGroup => from groupName in Gen.OneOfConst(groupNames)
|
||||
select productGroup with { Name = groupName })
|
||||
.SequenceToFrozenSet(productGroups.Comparer);
|
||||
}
|
||||
|
||||
|
@ -221,8 +223,8 @@ public record ServiceModel
|
|||
|
||||
var tagNames = tags.Select(tag => tag.Name).ToArray();
|
||||
|
||||
return productTags.Map(productTag => from tagName in Gen.OneOfConst(tagNames)
|
||||
select productTag with { Name = tagName })
|
||||
return productTags.Select(productTag => from tagName in Gen.OneOfConst(tagNames)
|
||||
select productTag with { Name = tagName })
|
||||
.SequenceToFrozenSet(productTags.Comparer);
|
||||
}
|
||||
|
||||
|
@ -236,17 +238,17 @@ public record ServiceModel
|
|||
|
||||
var apiNames = apis.Select(api => api.Name).ToArray();
|
||||
|
||||
return productApis.Map(productApi => from apiName in Gen.OneOfConst(apiNames)
|
||||
select productApi with { Name = apiName })
|
||||
return productApis.Select(productApi => from apiName in Gen.OneOfConst(apiNames)
|
||||
select productApi with { Name = apiName })
|
||||
.SequenceToFrozenSet(productApis.Comparer);
|
||||
}
|
||||
|
||||
public static Gen<FrozenSet<GatewayModel>> UpdateGateways(FrozenSet<GatewayModel> gateways, ICollection<ApiModel> apis) =>
|
||||
gateways.Map(gateway => from gatewayApis in UpdateGatewayApis(gateway.Apis, apis)
|
||||
select gateway with
|
||||
{
|
||||
Apis = gatewayApis
|
||||
})
|
||||
gateways.Select(gateway => from gatewayApis in UpdateGatewayApis(gateway.Apis, apis)
|
||||
select gateway with
|
||||
{
|
||||
Apis = gatewayApis
|
||||
})
|
||||
.SequenceToFrozenSet(gateways.Comparer);
|
||||
|
||||
private static Gen<FrozenSet<GatewayApiModel>> UpdateGatewayApis(FrozenSet<GatewayApiModel> gatewayApis, ICollection<ApiModel> apis)
|
||||
|
@ -259,8 +261,8 @@ public record ServiceModel
|
|||
|
||||
var apiNames = apis.Select(api => api.Name).ToArray();
|
||||
|
||||
return gatewayApis.Map(gatewayApi => from apiName in Gen.OneOfConst(apiNames)
|
||||
select gatewayApi with { Name = apiName })
|
||||
return gatewayApis.Select(gatewayApi => from apiName in Gen.OneOfConst(apiNames)
|
||||
select gatewayApi with { Name = apiName })
|
||||
.SequenceToFrozenSet(gatewayApis.Comparer);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using CsCheck;
|
||||
using LanguageExt;
|
||||
using Nito.Comparers;
|
||||
using System.Collections.Frozen;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -55,8 +54,6 @@ public sealed record SubscriptionModel
|
|||
Generator.AlphaNumericStringBetween(10, 20);
|
||||
|
||||
public static Gen<FrozenSet<SubscriptionModel>> GenerateSet() =>
|
||||
Generate().FrozenSetOf(EqualityComparerBuilder.For<SubscriptionModel>()
|
||||
.EquateBy(x => x.Name)
|
||||
.ThenEquateBy(x => x.DisplayName),
|
||||
0, 10);
|
||||
Generate().FrozenSetOf(x => x.Name, 0, 10)
|
||||
.DistinctBy(x => x.DisplayName);
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using CsCheck;
|
||||
using LanguageExt;
|
||||
using Nito.Comparers;
|
||||
using System.Collections.Frozen;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -28,8 +27,6 @@ public sealed record TagModel
|
|||
Generator.AlphaNumericStringBetween(10, 20);
|
||||
|
||||
public static Gen<FrozenSet<TagModel>> GenerateSet() =>
|
||||
Generate().FrozenSetOf(EqualityComparerBuilder.For<TagModel>()
|
||||
.EquateBy(x => x.Name)
|
||||
.ThenEquateBy(x => x.DisplayName),
|
||||
0, 10);
|
||||
Generate().FrozenSetOf(x => x.Name, 0, 10)
|
||||
.DistinctBy(x => x.DisplayName);
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using CsCheck;
|
||||
using LanguageExt;
|
||||
using Nito.Comparers;
|
||||
using System.Collections.Frozen;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -74,8 +73,6 @@ public sealed record VersionSetModel
|
|||
select lorem.Paragraph();
|
||||
|
||||
public static Gen<FrozenSet<VersionSetModel>> GenerateSet() =>
|
||||
Generate().FrozenSetOf(EqualityComparerBuilder.For<VersionSetModel>()
|
||||
.EquateBy(x => x.Name)
|
||||
.ThenEquateBy(x => x.DisplayName),
|
||||
0, 10);
|
||||
Generate().FrozenSetOf(x => x.Name, 0, 10)
|
||||
.DistinctBy(x => x.DisplayName);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
using CsCheck;
|
||||
using LanguageExt;
|
||||
using System.Collections.Frozen;
|
||||
using System.Linq;
|
||||
|
||||
namespace common.tests;
|
||||
|
||||
public sealed record WorkspaceModel
|
||||
{
|
||||
public required WorkspaceName Name { get; init; }
|
||||
public required string DisplayName { get; init; }
|
||||
public Option<string> Description { get; init; }
|
||||
|
||||
public static Gen<WorkspaceModel> Generate() =>
|
||||
from name in GenerateName()
|
||||
from displayName in GenerateDisplayName()
|
||||
from description in GenerateDescription().OptionOf()
|
||||
select new WorkspaceModel
|
||||
{
|
||||
Name = name,
|
||||
DisplayName = displayName,
|
||||
Description = description
|
||||
};
|
||||
|
||||
public static Gen<WorkspaceName> GenerateName() =>
|
||||
from name in Generator.AlphaNumericStringBetween(10, 20)
|
||||
select WorkspaceName.From(name);
|
||||
|
||||
public static Gen<string> GenerateDisplayName() =>
|
||||
Generator.AlphaNumericStringBetween(10, 20);
|
||||
|
||||
public static Gen<string> GenerateDescription() =>
|
||||
from lorem in Generator.Lorem
|
||||
select lorem.Paragraph();
|
||||
|
||||
public static Gen<FrozenSet<WorkspaceModel>> GenerateSet() =>
|
||||
Generate().FrozenSetOf(x => x.Name, 0, 10)
|
||||
.DistinctBy(x => x.DisplayName);
|
||||
}
|
|
@ -5,12 +5,12 @@
|
|||
<CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AnalysisLevel>8-all</AnalysisLevel>
|
||||
<WarningsNotAsErrors>CA1034,CA1062,CA1724,CA2007,CA1848,CA1716</WarningsNotAsErrors>
|
||||
<WarningsNotAsErrors>CA1034,CA1062,CA1724,CA2007,CA1848,CA1716,NU1903</WarningsNotAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bogus" Version="35.5.1" />
|
||||
<PackageReference Include="Bogus" Version="35.6.0" />
|
||||
<PackageReference Include="CsCheck" Version="3.2.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -293,17 +293,9 @@ public sealed record ApiDto
|
|||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public OAuth2AuthenticationSettingsContract? OAuth2 { get; init; }
|
||||
|
||||
[JsonPropertyName("oAuth2AuthenticationSettings")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableArray<OAuth2AuthenticationSettingsContract>? OAuth2AuthenticationSettings { get; init; }
|
||||
|
||||
[JsonPropertyName("openid")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public OpenIdAuthenticationSettingsContract? OpenId { get; init; }
|
||||
|
||||
[JsonPropertyName("openidAuthenticationSettings")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableArray<OpenIdAuthenticationSettingsContract>? OpenIdAuthenticationSettings { get; init; }
|
||||
}
|
||||
|
||||
public record OAuth2AuthenticationSettingsContract
|
||||
|
@ -438,17 +430,6 @@ public static class ApiModule
|
|||
return content.ToObjectFromJson<ApiDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<ApiDto>> TryGetDto(this ApiUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<ApiDto>())
|
||||
.Match(Option<ApiDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<ApiDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<BinaryData>> TryGetSpecificationContents(this ApiUri apiUri, ApiSpecification specification, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
if (specification is ApiSpecification.GraphQl)
|
||||
|
@ -664,7 +645,7 @@ public static class ApiModule
|
|||
}
|
||||
}
|
||||
|
||||
public static async ValueTask PutGraphQlSchema(this ApiUri uri, string schema, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
public static async ValueTask PutGraphQlSchema(this ApiUri uri, BinaryData schema, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var contents = BinaryData.FromObjectAsJson(new JsonObject()
|
||||
{
|
||||
|
@ -673,7 +654,7 @@ public static class ApiModule
|
|||
["contentType"] = "application/vnd.ms-azure-apim.graphql.schema",
|
||||
["document"] = new JsonObject()
|
||||
{
|
||||
["value"] = schema
|
||||
["value"] = schema.ToString()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -691,13 +672,9 @@ public static class ApiModule
|
|||
.AppendPathSegment("graphql")
|
||||
.ToUri();
|
||||
|
||||
var schemaJsonEither = await pipeline.TryGetJsonObject(schemaUri, cancellationToken);
|
||||
var schemaJsonOption = await pipeline.GetJsonObjectOption(schemaUri, cancellationToken);
|
||||
|
||||
return schemaJsonEither.Map(GetGraphQlSpecificationFromSchemaResponse)
|
||||
.Match(Option<BinaryData>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<BinaryData>.None
|
||||
: throw response.ToHttpRequestException(schemaUri));
|
||||
return schemaJsonOption.Map(GetGraphQlSpecificationFromSchemaResponse);
|
||||
}
|
||||
|
||||
private static BinaryData GetGraphQlSpecificationFromSchemaResponse(JsonObject responseJson)
|
||||
|
@ -724,11 +701,11 @@ public static class ApiModule
|
|||
.Select(directory => new ApiInformationFile { Parent = directory })
|
||||
.Where(informationFile => informationFile.ToFileInfo().Exists());
|
||||
|
||||
public static IAsyncEnumerable<ApiSpecificationFile> ListSpecificationFiles(ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
public static IAsyncEnumerable<ApiSpecificationFile> ListSpecificationFiles(ManagementServiceDirectory serviceDirectory) =>
|
||||
ListDirectories(serviceDirectory)
|
||||
.SelectMany(directory => directory.ToDirectoryInfo().ListFiles("*"))
|
||||
.ToAsyncEnumerable()
|
||||
.Choose(async file => await ApiSpecificationFile.TryParse(file, serviceDirectory, cancellationToken));
|
||||
.Choose(async (file, cancellationToken) => await ApiSpecificationFile.TryParse(file, serviceDirectory, cancellationToken));
|
||||
|
||||
public static async ValueTask WriteDto(this ApiInformationFile file, ApiDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -745,26 +722,9 @@ public static class ApiModule
|
|||
public static async ValueTask WriteSpecification(this ApiSpecificationFile file, BinaryData contents, CancellationToken cancellationToken) =>
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(contents, cancellationToken);
|
||||
|
||||
public static FileInfo ToFileInfo(this ApiSpecificationFile file) =>
|
||||
file switch
|
||||
{
|
||||
GraphQlSpecificationFile graphQl => graphQl.ToFileInfo(),
|
||||
WadlSpecificationFile wadl => wadl.ToFileInfo(),
|
||||
WsdlSpecificationFile wsdl => wsdl.ToFileInfo(),
|
||||
OpenApiSpecificationFile openApi => openApi switch
|
||||
{
|
||||
YamlOpenApiSpecificationFile yaml => yaml.ToFileInfo(),
|
||||
JsonOpenApiSpecificationFile json => json.ToFileInfo(),
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
public static async ValueTask<BinaryData> ReadContents(this ApiSpecificationFile file, CancellationToken cancellationToken) =>
|
||||
await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
|
||||
public static Option<VersionSetName> TryGetVersionSetName(ApiDto dto) =>
|
||||
from versionSetId in Prelude.Optional(dto.Properties.ApiVersionSetId)
|
||||
from versionSetNameString in versionSetId.Split('/').LastOrNone()
|
||||
from versionSetNameString in versionSetId.Split('/')
|
||||
.LastOrNone()
|
||||
select VersionSetName.From(versionSetNameString);
|
||||
}
|
|
@ -123,17 +123,6 @@ public static class ApiOperationPolicyModule
|
|||
return content.ToObjectFromJson<ApiOperationPolicyDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<ApiOperationPolicyDto>> TryGetDto(this ApiOperationPolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<ApiOperationPolicyDto>())
|
||||
.Match(Option<ApiOperationPolicyDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<ApiOperationPolicyDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this ApiOperationPolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -125,13 +124,9 @@ public static class ApiPolicyModule
|
|||
|
||||
public static async ValueTask<Option<ApiPolicyDto>> TryGetDto(this ApiPolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
var option = await pipeline.GetContentOption(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<ApiPolicyDto>())
|
||||
.Match(Option<ApiPolicyDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<ApiPolicyDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
return option.Map(content => content.ToObjectFromJson<ApiPolicyDto>());
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this ApiPolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
|
|
|
@ -4,7 +4,6 @@ using Microsoft.OpenApi.Readers;
|
|||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -93,8 +92,7 @@ public abstract record ApiSpecificationFile : ResourceFile
|
|||
select specificationFile as ApiSpecificationFile;
|
||||
|
||||
return await ImmutableArray.Create(tryParseGraphQl, tryParseWadl, tryParseWsdl, tryParseOpenApi)
|
||||
.ToAsyncEnumerable()
|
||||
.Pick(async f => await f(), cancellationToken);
|
||||
.Pick(async (f, cancellationToken) => await f(), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,7 +114,7 @@ public sealed record GraphQlSpecificationFile : ApiSpecificationFile
|
|||
: Option<GraphQlSpecificationFile>.None;
|
||||
}
|
||||
|
||||
public sealed record class WadlSpecificationFile : ApiSpecificationFile
|
||||
public sealed record WadlSpecificationFile : ApiSpecificationFile
|
||||
{
|
||||
public override ApiSpecification Specification { get; } = new ApiSpecification.Wadl();
|
||||
|
||||
|
@ -180,8 +178,7 @@ public abstract record OpenApiSpecificationFile : ApiSpecificationFile
|
|||
select json as OpenApiSpecificationFile;
|
||||
|
||||
return await ImmutableArray.Create(tryParseYaml, tryParseJson)
|
||||
.ToAsyncEnumerable()
|
||||
.Pick(async f => await f(), cancellationToken);
|
||||
.Pick(async (f, cancellationToken) => await f(), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -143,20 +143,21 @@ public static class ApiTagModule
|
|||
public static IEnumerable<ApiTagInformationFile> ListInformationFiles(ApiName apiName, ManagementServiceDirectory serviceDirectory) =>
|
||||
ListApiTagsDirectories(apiName, serviceDirectory)
|
||||
.SelectMany(ListApiTagDirectories)
|
||||
.Select(directory => ApiTagInformationFile.From(directory.Name, apiName, serviceDirectory));
|
||||
.Select(directory => ApiTagInformationFile.From(directory.Name, apiName, serviceDirectory))
|
||||
.Where(informationFile => informationFile.ToFileInfo().Exists());
|
||||
|
||||
private static IEnumerable<ApiTagsDirectory> ListApiTagsDirectories(ApiName apiName, ManagementServiceDirectory serviceDirectory) =>
|
||||
ApiDirectory.From(apiName, serviceDirectory)
|
||||
.ToDirectoryInfo()
|
||||
.ListDirectories("*")
|
||||
.Where(ApiTagsDirectory.IsDirectoryNameValid)
|
||||
.Select(_ => ApiTagsDirectory.From(apiName, serviceDirectory));
|
||||
.ToDirectoryInfo()
|
||||
.ListDirectories("*")
|
||||
.Where(ApiTagsDirectory.IsDirectoryNameValid)
|
||||
.Select(_ => ApiTagsDirectory.From(apiName, serviceDirectory));
|
||||
|
||||
private static IEnumerable<ApiTagDirectory> ListApiTagDirectories(ApiTagsDirectory apiTagsDirectory) =>
|
||||
apiTagsDirectory.ToDirectoryInfo()
|
||||
.ListDirectories("*")
|
||||
.Choose(directory => from name in ApiTagDirectory.TryParseApiTagName(directory)
|
||||
select new ApiTagDirectory { Name = name, Parent = apiTagsDirectory });
|
||||
.ListDirectories("*")
|
||||
.Choose(directory => from name in ApiTagDirectory.TryParseApiTagName(directory)
|
||||
select new ApiTagDirectory { Name = name, Parent = apiTagsDirectory });
|
||||
|
||||
public static async ValueTask WriteDto(this ApiTagInformationFile file, ApiTagDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
|
|
|
@ -1,24 +1,17 @@
|
|||
using Azure.Core;
|
||||
using Azure.Core.Pipeline;
|
||||
using Azure.Identity;
|
||||
using Azure.ResourceManager;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Http.Resilience;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Polly.Retry;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
|
||||
namespace common;
|
||||
|
||||
|
@ -33,232 +26,205 @@ public sealed record AzureEnvironment(Uri AuthorityHost, string DefaultScope, Ur
|
|||
public static AzureEnvironment China { get; } = new(AzureAuthorityHosts.AzureChina, ArmEnvironment.AzureChina.DefaultScope, ArmEnvironment.AzureChina.Endpoint);
|
||||
}
|
||||
|
||||
public class ApimHttpClient(HttpClient client)
|
||||
public sealed record SubscriptionId : NonEmptyString
|
||||
{
|
||||
public HttpClient HttpClient { get; } = client;
|
||||
public SubscriptionId(string value) : base(value) { }
|
||||
}
|
||||
|
||||
public static class ApimHttpClientExtensions
|
||||
public sealed record ResourceGroupName : NonEmptyString
|
||||
{
|
||||
public static IServiceCollection ConfigureApimHttpClient(this IServiceCollection services)
|
||||
{
|
||||
services.AddHttpClient<ApimHttpClient>()
|
||||
.AddHttpMessageHandler<LoggingHandler>()
|
||||
.AddHttpMessageHandler<TokenCredentialHandler>()
|
||||
.AddStandardResilienceHandler(ConfigureResilienceOptions);
|
||||
|
||||
services.TryAddTransient<LoggingHandler>();
|
||||
services.TryAddTransient<TokenCredentialHandler>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static void ConfigureResilienceOptions(HttpStandardResilienceOptions options)
|
||||
{
|
||||
options.Retry.ShouldHandle = ShouldRetry;
|
||||
}
|
||||
|
||||
private static async ValueTask<bool> ShouldRetry(RetryPredicateArguments<HttpResponseMessage> arguments) =>
|
||||
HttpClientResiliencePredicates.IsTransient(arguments.Outcome)
|
||||
|| arguments.Outcome switch
|
||||
{
|
||||
{ Result: { } response } =>
|
||||
await HasManagementApiRequestFailed(response, arguments.Context.CancellationToken)
|
||||
|| await IsEntityNotFound(response, arguments.Context.CancellationToken),
|
||||
_ => false
|
||||
};
|
||||
|
||||
private static async ValueTask<bool> HasManagementApiRequestFailed(HttpResponseMessage response, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var responseJsonOption = await Common.TryGetJsonObjectCopy(response.Content, cancellationToken);
|
||||
|
||||
return responseJsonOption.Bind(responseJson => responseJson.TryGetJsonObjectProperty("error")
|
||||
.Bind(error => error.TryGetStringProperty("code"))
|
||||
.ToOption()
|
||||
.Where(code => code.Equals("ManagementApiRequestFailed", StringComparison.OrdinalIgnoreCase)))
|
||||
.IsSome;
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static async ValueTask<bool> IsEntityNotFound(HttpResponseMessage response, CancellationToken cancellationToken)
|
||||
{
|
||||
if (response.StatusCode is not HttpStatusCode.BadRequest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var content = await Common.GetStringCopy(response.Content, cancellationToken);
|
||||
return content.Contains("Entity with specified identifier not found", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
public ResourceGroupName(string value) : base(value) { }
|
||||
}
|
||||
|
||||
# pragma warning disable CA1812
|
||||
file sealed class LoggingHandler(ILoggerFactory loggerFactory) : DelegatingHandler
|
||||
public static class AzureModule
|
||||
{
|
||||
private readonly ILogger logger = loggerFactory.CreateLogger(nameof(ApimHttpClient));
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
private static void ConfigureAzureEnvironment(IHostApplicationBuilder builder)
|
||||
{
|
||||
await LogRequest(request, cancellationToken);
|
||||
|
||||
var stopWatch = Stopwatch.StartNew();
|
||||
var response = await base.SendAsync(request, cancellationToken);
|
||||
stopWatch.Stop();
|
||||
|
||||
await LogResponse(response, stopWatch.Elapsed, cancellationToken);
|
||||
|
||||
return response;
|
||||
builder.Services.TryAddSingleton(GetAzureEnvironment);
|
||||
}
|
||||
|
||||
private async ValueTask LogRequest(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
private static AzureEnvironment GetAzureEnvironment(IServiceProvider provider)
|
||||
{
|
||||
if (logger.IsEnabled(LogLevel.Trace))
|
||||
{
|
||||
logger.LogTrace("""
|
||||
Starting request
|
||||
Method: {HttpMethod}
|
||||
Uri: {Uri}
|
||||
Content: {RequestContent}
|
||||
""",
|
||||
request.Method,
|
||||
request.RequestUri,
|
||||
await GetContentString(request.Content, request.Headers, cancellationToken));
|
||||
}
|
||||
else if (logger.IsEnabled(LogLevel.Debug))
|
||||
{
|
||||
logger.LogDebug("""
|
||||
Starting request
|
||||
Method: {HttpMethod}
|
||||
Uri: {Uri}
|
||||
""",
|
||||
request.Method,
|
||||
request.RequestUri);
|
||||
}
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
return configuration.TryGetValue("AZURE_CLOUD_ENVIRONMENT")
|
||||
.Map(value => value switch
|
||||
{
|
||||
"AzureGlobalCloud" or nameof(ArmEnvironment.AzurePublicCloud) => AzureEnvironment.Public,
|
||||
"AzureChinaCloud" or nameof(ArmEnvironment.AzureChina) => AzureEnvironment.China,
|
||||
"AzureUSGovernment" or nameof(ArmEnvironment.AzureGovernment) => AzureEnvironment.USGovernment,
|
||||
"AzureGermanCloud" or nameof(ArmEnvironment.AzureGermany) => AzureEnvironment.Germany,
|
||||
_ => throw new InvalidOperationException($"AZURE_CLOUD_ENVIRONMENT is invalid. Valid values are {nameof(ArmEnvironment.AzurePublicCloud)}, {nameof(ArmEnvironment.AzureChina)}, {nameof(ArmEnvironment.AzureGovernment)}, {nameof(ArmEnvironment.AzureGermany)}")
|
||||
})
|
||||
.IfNone(() => AzureEnvironment.Public);
|
||||
}
|
||||
|
||||
private static async ValueTask<string> GetContentString(HttpContent? content, HttpHeaders headers, CancellationToken cancellationToken) =>
|
||||
content switch
|
||||
{
|
||||
null => "<null>",
|
||||
_ => HeaderIsJson(headers)
|
||||
? await Common.GetStringCopy(content, cancellationToken)
|
||||
: "<non-json>"
|
||||
};
|
||||
|
||||
private static bool HeaderIsJson(HttpHeaders headers) =>
|
||||
headers.TryGetValues("Content-Type", out var values) &&
|
||||
values.Contains("application/json", StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private async ValueTask LogResponse(HttpResponseMessage response, TimeSpan duration, CancellationToken cancellationToken)
|
||||
private static void ConfigureTokenCredential(IHostApplicationBuilder builder)
|
||||
{
|
||||
if (logger.IsEnabled(LogLevel.Trace))
|
||||
{
|
||||
logger.LogTrace("""
|
||||
Starting request
|
||||
Method: {HttpMethod}
|
||||
Uri: {Uri}
|
||||
Duration (hh:mm:ss): {Duration}
|
||||
Content: {RequestContent}
|
||||
""",
|
||||
response.RequestMessage?.Method,
|
||||
response.RequestMessage?.RequestUri,
|
||||
duration.ToString("c"),
|
||||
await GetContentString(response.Content, response.Headers, cancellationToken));
|
||||
}
|
||||
else if (logger.IsEnabled(LogLevel.Debug))
|
||||
{
|
||||
logger.LogDebug("""
|
||||
Starting request
|
||||
Method: {HttpMethod}
|
||||
Duration (hh:mm:ss): {Duration}
|
||||
Uri: {Uri}
|
||||
""",
|
||||
response.RequestMessage?.Method,
|
||||
response.RequestMessage?.RequestUri,
|
||||
duration.ToString("c"));
|
||||
}
|
||||
ConfigureAzureEnvironment(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetTokenCredential);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class TokenCredentialHandler(TokenCredential tokenCredential) : DelegatingHandler
|
||||
{
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
private static TokenCredential GetTokenCredential(IServiceProvider provider)
|
||||
{
|
||||
if (request.RequestUri is null)
|
||||
var environment = provider.GetRequiredService<AzureEnvironment>();
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
return configuration.TryGetValue("AZURE_BEARER_TOKEN")
|
||||
.Map(GetCredentialFromToken)
|
||||
.IfNone(() => GetDefaultAzureCredential(environment.AuthorityHost));
|
||||
|
||||
|
||||
static TokenCredential GetCredentialFromToken(string token)
|
||||
{
|
||||
return await base.SendAsync(request, cancellationToken);
|
||||
var jsonWebToken = new JsonWebToken(token);
|
||||
var expirationDate = new DateTimeOffset(jsonWebToken.ValidTo);
|
||||
var accessToken = new AccessToken(token, expirationDate);
|
||||
|
||||
return DelegatedTokenCredential.Create((context, cancellationToken) => accessToken);
|
||||
}
|
||||
|
||||
request.Headers.Authorization = await GetAuthenticationHeader(request.RequestUri, cancellationToken);
|
||||
|
||||
return await base.SendAsync(request, cancellationToken);
|
||||
static DefaultAzureCredential GetDefaultAzureCredential(Uri azureAuthorityHost) =>
|
||||
new(new DefaultAzureCredentialOptions
|
||||
{
|
||||
AuthorityHost = azureAuthorityHost
|
||||
});
|
||||
}
|
||||
|
||||
private async ValueTask<AuthenticationHeaderValue> GetAuthenticationHeader(Uri uri, CancellationToken cancellationToken)
|
||||
public static void ConfigureHttpPipeline(IHostApplicationBuilder builder)
|
||||
{
|
||||
var accessToken = await GetAccessToken(uri, cancellationToken);
|
||||
ConfigureTokenCredential(builder);
|
||||
ConfigureAzureEnvironment(builder);
|
||||
|
||||
return new AuthenticationHeaderValue("Bearer", accessToken.Token);
|
||||
builder.Services.TryAddSingleton(GetHttpPipeline);
|
||||
}
|
||||
|
||||
private async ValueTask<AccessToken> GetAccessToken(Uri uri, CancellationToken cancellationToken)
|
||||
private static HttpPipeline GetHttpPipeline(IServiceProvider provider)
|
||||
{
|
||||
var scopeUrl = uri.GetLeftPart(UriPartial.Authority)
|
||||
.AppendPathSegment(".default")
|
||||
.ToString();
|
||||
var tokenCredential = provider.GetRequiredService<TokenCredential>();
|
||||
var azureEnvironment = provider.GetRequiredService<AzureEnvironment>();
|
||||
|
||||
return await GetAccessToken([scopeUrl], cancellationToken);
|
||||
var clientOptions = ClientOptions.Default;
|
||||
clientOptions.RetryPolicy = new CommonRetryPolicy();
|
||||
|
||||
var bearerAuthenticationPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, azureEnvironment.DefaultScope);
|
||||
|
||||
var logger = provider.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(HttpPipeline));
|
||||
var loggingPolicy = new ILoggerHttpPipelinePolicy(logger);
|
||||
|
||||
var version = Assembly.GetEntryAssembly()?.GetName().Version ?? new Version("-1");
|
||||
var telemetryPolicy = new TelemetryPolicy(version);
|
||||
|
||||
return HttpPipelineBuilder.Build(clientOptions, bearerAuthenticationPolicy, loggingPolicy, telemetryPolicy);
|
||||
}
|
||||
|
||||
private async ValueTask<AccessToken> GetAccessToken(string[] scopes, CancellationToken cancellationToken)
|
||||
private static void ConfigureManagementServiceName(IHostApplicationBuilder builder)
|
||||
{
|
||||
var context = new TokenRequestContext(scopes);
|
||||
|
||||
return await tokenCredential.GetTokenAsync(context, cancellationToken);
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1812
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static async ValueTask<Stream> GetStreamCopy(HttpContent content, CancellationToken cancellationToken)
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
await content.CopyToAsync(stream, cancellationToken);
|
||||
stream.Position = 0;
|
||||
|
||||
return stream;
|
||||
builder.Services.TryAddSingleton(GetManagementServiceName);
|
||||
}
|
||||
|
||||
public static async ValueTask<string> GetStringCopy(HttpContent content, CancellationToken cancellationToken)
|
||||
private static ManagementServiceName GetManagementServiceName(IServiceProvider provider)
|
||||
{
|
||||
using var stream = await GetStreamCopy(content, cancellationToken);
|
||||
var data = await BinaryData.FromStreamAsync(stream, cancellationToken);
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
return data.ToString();
|
||||
var name = configuration.TryGetValue("API_MANAGEMENT_SERVICE_NAME")
|
||||
.IfNone(() => configuration.GetValue("apimServiceName"));
|
||||
|
||||
return ManagementServiceName.From(name);
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<JsonObject>> TryGetJsonObjectCopy(HttpContent content, CancellationToken cancellationToken)
|
||||
public static void ConfigureManagementServiceUri(IHostApplicationBuilder builder)
|
||||
{
|
||||
using var stream = await GetStreamCopy(content, cancellationToken);
|
||||
ConfigureManagementServiceProviderUri(builder);
|
||||
ConfigureManagementServiceName(builder);
|
||||
|
||||
try
|
||||
{
|
||||
var node = await JsonNode.ParseAsync(stream, cancellationToken: cancellationToken);
|
||||
builder.Services.TryAddSingleton(GetManagementServiceUri);
|
||||
}
|
||||
|
||||
return node is JsonObject jsonObject
|
||||
? Option<JsonObject>.Some(jsonObject)
|
||||
: Option<JsonObject>.None;
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return Option<JsonObject>.None;
|
||||
}
|
||||
private static ManagementServiceUri GetManagementServiceUri(IServiceProvider provider)
|
||||
{
|
||||
var serviceProviderUri = provider.GetRequiredService<ManagementServiceProviderUri>();
|
||||
var serviceName = provider.GetRequiredService<ManagementServiceName>();
|
||||
|
||||
var uri = serviceProviderUri.ToUri()
|
||||
.AppendPathSegment(serviceName)
|
||||
.ToUri();
|
||||
|
||||
return ManagementServiceUri.From(uri);
|
||||
}
|
||||
|
||||
public static void ConfigureManagementServiceProviderUri(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureAzureEnvironment(builder);
|
||||
ConfigureSubscriptionId(builder);
|
||||
ConfigureResourceGroupName(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetManagementServiceProviderUri);
|
||||
}
|
||||
|
||||
private static ManagementServiceProviderUri GetManagementServiceProviderUri(IServiceProvider provider)
|
||||
{
|
||||
var azureEnvironment = provider.GetRequiredService<AzureEnvironment>();
|
||||
var subscriptionId = provider.GetRequiredService<SubscriptionId>();
|
||||
var resourceGroupName = provider.GetRequiredService<ResourceGroupName>();
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var apiVersion = configuration.TryGetValue("ARM_API_VERSION")
|
||||
.IfNone(() => "2023-09-01-preview");
|
||||
|
||||
var uri = azureEnvironment.ManagementEndpoint
|
||||
.AppendPathSegment("subscriptions")
|
||||
.AppendPathSegment(subscriptionId)
|
||||
.AppendPathSegment("resourceGroups")
|
||||
.AppendPathSegment(resourceGroupName)
|
||||
.AppendPathSegment("providers/Microsoft.ApiManagement/service")
|
||||
.SetQueryParam("api-version", apiVersion)
|
||||
.ToUri();
|
||||
|
||||
return ManagementServiceProviderUri.From(uri);
|
||||
}
|
||||
|
||||
private static void ConfigureSubscriptionId(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetSubscriptionId);
|
||||
}
|
||||
|
||||
private static SubscriptionId GetSubscriptionId(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var subscriptionId = configuration.GetValue("AZURE_SUBSCRIPTION_ID");
|
||||
|
||||
return new SubscriptionId(subscriptionId);
|
||||
}
|
||||
|
||||
private static void ConfigureResourceGroupName(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetResourceGroupName);
|
||||
}
|
||||
|
||||
private static ResourceGroupName GetResourceGroupName(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var resourceGroupName = configuration.GetValue("AZURE_RESOURCE_GROUP_NAME");
|
||||
|
||||
return new ResourceGroupName(resourceGroupName);
|
||||
}
|
||||
|
||||
public static void ConfigureManagementServiceDirectory(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetManagementServiceDirectory);
|
||||
}
|
||||
|
||||
private static ManagementServiceDirectory GetManagementServiceDirectory(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var directoryPath = configuration.GetValue("API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH");
|
||||
var directory = new DirectoryInfo(directoryPath);
|
||||
|
||||
return ManagementServiceDirectory.From(directory);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
|
@ -27,7 +26,8 @@ public sealed record BackendsUri : ResourceUri
|
|||
|
||||
private static string PathSegment { get; } = "backends";
|
||||
|
||||
protected override Uri Value => ServiceUri.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
protected override Uri Value =>
|
||||
ServiceUri.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static BackendsUri From(ManagementServiceUri serviceUri) =>
|
||||
new() { ServiceUri = serviceUri };
|
||||
|
@ -36,9 +36,11 @@ public sealed record BackendsUri : ResourceUri
|
|||
public sealed record BackendUri : ResourceUri
|
||||
{
|
||||
public required BackendsUri Parent { get; init; }
|
||||
|
||||
public required BackendName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
protected override Uri Value =>
|
||||
Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static BackendUri From(BackendName name, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
|
@ -61,9 +63,8 @@ public sealed record BackendsDirectory : ResourceDirectory
|
|||
new() { ServiceDirectory = serviceDirectory };
|
||||
|
||||
public static Option<BackendsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
directory is not null &&
|
||||
directory.Name == Name &&
|
||||
directory.Parent?.FullName == serviceDirectory.ToDirectoryInfo().FullName
|
||||
directory?.Name == Name &&
|
||||
directory?.Parent?.FullName == serviceDirectory.ToDirectoryInfo().FullName
|
||||
? new BackendsDirectory { ServiceDirectory = serviceDirectory }
|
||||
: Option<BackendsDirectory>.None;
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ public sealed record BackendDirectory : ResourceDirectory
|
|||
public required BackendName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.Value);
|
||||
|
||||
public static BackendDirectory From(BackendName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
|
@ -86,17 +87,19 @@ public sealed record BackendDirectory : ResourceDirectory
|
|||
|
||||
public static Option<BackendDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in BackendsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
let name = BackendName.From(directory!.Name)
|
||||
select new BackendDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = BackendName.From(directory!.Name)
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record BackendInformationFile : ResourceFile
|
||||
{
|
||||
public required BackendDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "backendInformation.json";
|
||||
|
||||
public static string Name { get; } = "backendInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
@ -104,17 +107,17 @@ public sealed record BackendInformationFile : ResourceFile
|
|||
public static BackendInformationFile From(BackendName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = new BackendDirectory
|
||||
{
|
||||
Parent = BackendsDirectory.From(serviceDirectory),
|
||||
Name = name
|
||||
}
|
||||
Parent = BackendDirectory.From(name, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<BackendInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null && file.Name == Name
|
||||
file is not null &&
|
||||
file.Name == Name
|
||||
? from parent in BackendDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new BackendInformationFile { Parent = parent }
|
||||
select new BackendInformationFile
|
||||
{
|
||||
Parent = parent
|
||||
}
|
||||
: Option<BackendInformationFile>.None;
|
||||
}
|
||||
|
||||
|
@ -277,23 +280,25 @@ public static class BackendModule
|
|||
{
|
||||
public static async ValueTask DeleteAll(this BackendsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await uri.ListNames(pipeline, cancellationToken)
|
||||
.IterParallel(async name => await BackendUri.From(name, uri.ServiceUri)
|
||||
.Delete(pipeline, cancellationToken),
|
||||
cancellationToken);
|
||||
.IterParallel(async name =>
|
||||
{
|
||||
var backendUri = new BackendUri { Parent = uri, Name = name };
|
||||
await backendUri.Delete(pipeline, cancellationToken);
|
||||
}, cancellationToken);
|
||||
|
||||
public static IAsyncEnumerable<BackendName> ListNames(this BackendsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(BackendName.From);
|
||||
|
||||
public static IAsyncEnumerable<(BackendName Name, BackendDto Dto)> List(this BackendsUri backendsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
backendsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new BackendUri { Parent = backendsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
public static IAsyncEnumerable<(BackendName Name, BackendDto Dto)> List(this BackendsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
uri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var backendUri = new BackendUri { Parent = uri, Name = name };
|
||||
var dto = await backendUri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<BackendDto> GetDto(this BackendUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -301,17 +306,6 @@ public static class BackendModule
|
|||
return content.ToObjectFromJson<BackendDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<BackendDto>> TryGetDto(this BackendUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<BackendDto>())
|
||||
.Match(Option<BackendDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<BackendDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this BackendUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
@ -325,16 +319,20 @@ public static class BackendModule
|
|||
{
|
||||
var backendsDirectory = BackendsDirectory.From(serviceDirectory);
|
||||
|
||||
return backendsDirectory.ToDirectoryInfo()
|
||||
.ListDirectories("*")
|
||||
.Select(directoryInfo => BackendName.From(directoryInfo.Name))
|
||||
.Select(name => new BackendDirectory { Parent = backendsDirectory, Name = name });
|
||||
return from backendsDirectoryInfo in backendsDirectory.ToDirectoryInfo().ListDirectories("*")
|
||||
let name = BackendName.From(backendsDirectoryInfo.Name)
|
||||
select new BackendDirectory
|
||||
{
|
||||
Parent = backendsDirectory,
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<BackendInformationFile> ListInformationFiles(ManagementServiceDirectory serviceDirectory) =>
|
||||
ListDirectories(serviceDirectory)
|
||||
.Select(directory => new BackendInformationFile { Parent = directory })
|
||||
.Where(informationFile => informationFile.ToFileInfo().Exists());
|
||||
from backendDirectory in ListDirectories(serviceDirectory)
|
||||
let informationFile = new BackendInformationFile { Parent = backendDirectory }
|
||||
where informationFile.ToFileInfo().Exists()
|
||||
select informationFile;
|
||||
|
||||
public static async ValueTask WriteDto(this BackendInformationFile file, BackendDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace common;
|
||||
|
||||
public abstract record ResourceName
|
||||
public abstract record NonEmptyString
|
||||
{
|
||||
protected ResourceName(string value)
|
||||
protected NonEmptyString(string value)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(value, nameof(value));
|
||||
Value = value;
|
||||
|
@ -14,11 +13,16 @@ public abstract record ResourceName
|
|||
|
||||
public string Value { get; }
|
||||
|
||||
public sealed override string ToString() => Value;
|
||||
}
|
||||
|
||||
public abstract record ResourceName : NonEmptyString
|
||||
{
|
||||
protected ResourceName(string value) : base(value) { }
|
||||
|
||||
public virtual bool Equals(ResourceName? other) => string.Equals(Value, other?.Value, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public override int GetHashCode() => Value.GetHashCode(StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public sealed override string ToString() => Value;
|
||||
}
|
||||
|
||||
public abstract record ResourceDirectory
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Yaml2JsonNode;
|
||||
|
@ -12,6 +18,8 @@ namespace common;
|
|||
|
||||
public record ConfigurationJson
|
||||
{
|
||||
private static readonly JsonNodeOptions nodeOptions = new() { PropertyNameCaseInsensitive = true };
|
||||
|
||||
public required JsonObject Value { get; init; }
|
||||
|
||||
public static ConfigurationJson From(IConfiguration configuration) =>
|
||||
|
@ -19,18 +27,18 @@ public record ConfigurationJson
|
|||
{
|
||||
Value = SerializeConfiguration(configuration) is JsonObject configurationJsonObject
|
||||
? configurationJsonObject
|
||||
: new JsonObject(JsonNodeExtensions.Options)
|
||||
: new JsonObject(nodeOptions)
|
||||
};
|
||||
|
||||
private static JsonNode? SerializeConfiguration(IConfiguration configuration)
|
||||
{
|
||||
var jsonObject = new JsonObject(JsonNodeExtensions.Options);
|
||||
var jsonObject = new JsonObject();
|
||||
|
||||
foreach (var child in configuration.GetChildren())
|
||||
{
|
||||
if (child.Path.EndsWith(":0", StringComparison.Ordinal))
|
||||
{
|
||||
var jsonArray = new JsonArray(JsonNodeExtensions.Options);
|
||||
var jsonArray = new JsonArray(nodeOptions);
|
||||
|
||||
foreach (var arrayChild in configuration.GetChildren())
|
||||
{
|
||||
|
@ -85,7 +93,7 @@ public record ConfigurationJson
|
|||
|
||||
return yamlStream.Documents switch
|
||||
{
|
||||
[] => new JsonObject(JsonNodeExtensions.Options),
|
||||
[] => new JsonObject(nodeOptions),
|
||||
[var document] => document.ToJsonNode()?.AsObject() ?? throw new JsonException("Failed to convert YAML to JSON."),
|
||||
_ => throw new JsonException("More than one YAML document was found.")
|
||||
};
|
||||
|
@ -157,4 +165,51 @@ public static class ConfigurationExtensions
|
|||
? Option<IConfigurationSection>.Some(section)
|
||||
: Option<IConfigurationSection>.None;
|
||||
}
|
||||
|
||||
public static IConfigurationBuilder AddUserSecretsWithLowestPriority(this IConfigurationBuilder builder, Assembly assembly, bool optional = true) =>
|
||||
builder.AddWithLowestPriority(b => b.AddUserSecrets(assembly, optional));
|
||||
|
||||
private static IConfigurationBuilder AddWithLowestPriority(this IConfigurationBuilder builder, Func<IConfigurationBuilder, IConfigurationBuilder> adder)
|
||||
{
|
||||
// Configuration sources added last have the highest priority. We empty existing sources,
|
||||
// add the new sources, and then add the existing sources back.
|
||||
var adderSources = adder(new ConfigurationBuilder()).Sources;
|
||||
var existingSources = builder.Sources;
|
||||
var sources = adderSources.Concat(existingSources)
|
||||
.ToImmutableArray();
|
||||
|
||||
builder.Sources.Clear();
|
||||
sources.Iter(source => builder.Add(source));
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigurationModule
|
||||
{
|
||||
public static void ConfigureConfigurationJson(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetConfigurationJson);
|
||||
}
|
||||
|
||||
private static ConfigurationJson GetConfigurationJson(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var configurationJson = ConfigurationJson.From(configuration);
|
||||
|
||||
return TryGetConfigurationJsonFromYaml(configuration)
|
||||
.Map(configurationJson.MergeWith)
|
||||
.IfNone(configurationJson);
|
||||
}
|
||||
|
||||
private static Option<ConfigurationJson> TryGetConfigurationJsonFromYaml(IConfiguration configuration) =>
|
||||
configuration.TryGetValue("CONFIGURATION_YAML_PATH")
|
||||
.Map(path => new FileInfo(path))
|
||||
.Where(file => file.Exists)
|
||||
.Map(file =>
|
||||
{
|
||||
using var reader = File.OpenText(file.FullName);
|
||||
return ConfigurationJson.FromYaml(reader);
|
||||
});
|
||||
}
|
|
@ -261,17 +261,6 @@ public static class DiagnosticModule
|
|||
return content.ToObjectFromJson<DiagnosticDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<DiagnosticDto>> TryGetDto(this DiagnosticUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<DiagnosticDto>())
|
||||
.Match(Option<DiagnosticDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<DiagnosticDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this DiagnosticUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
using LanguageExt.UnsafeValueAccess;
|
||||
using Nito.Comparers;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -14,15 +13,43 @@ namespace common;
|
|||
|
||||
public static class IEnumerableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed sequentially. The function returns after all actions have executed.
|
||||
/// </summary>
|
||||
public static void Iter<T>(this IEnumerable<T> enumerable, Action<T> action)
|
||||
{
|
||||
foreach (var t in enumerable)
|
||||
{
|
||||
action(t);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed sequentially. The function returns after all actions have executed.
|
||||
/// </summary>
|
||||
public static async ValueTask Iter<T>(this IEnumerable<T> enumerable, Func<T, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(async (t, _) => await action(t), maxDegreeOfParallelism: 1, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed in parallel. The function will wait for all actions to complete before returning.
|
||||
/// </summary>
|
||||
public static async ValueTask IterParallel<T>(this IEnumerable<T> enumerable, Func<T, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(async (t, _) => await action(t), maxDegreeOfParallelism: -1, cancellationToken);
|
||||
await enumerable.IterParallel(async (t, _) => await action(t), maxDegreeOfParallelism: -1, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed in parallel. The function will wait for all actions to complete before returning.
|
||||
/// </summary>
|
||||
public static async ValueTask IterParallel<T>(this IEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(action, maxDegreeOfParallelism: -1, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// <paramref name="maxDegreeOfParallelism"/> controls the maximum number of parallel actions. The function will wait for all actions to complete before returning.
|
||||
/// </summary>
|
||||
public static async ValueTask IterParallel<T>(this IEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask> action, int maxDegreeOfParallelism, CancellationToken cancellationToken)
|
||||
{
|
||||
var options = new ParallelOptions
|
||||
|
@ -34,71 +61,112 @@ public static class IEnumerableExtensions
|
|||
await Parallel.ForEachAsync(enumerable, parallelOptions: options, action);
|
||||
}
|
||||
|
||||
public static IAsyncEnumerable<T2> Choose<T, T2>(this IEnumerable<T> enumerable, Func<T, ValueTask<Option<T2>>> f) =>
|
||||
enumerable.ToAsyncEnumerable()
|
||||
.Choose(f);
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IEnumerable"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed in parallel. The function will wait for all actions to complete before returning.
|
||||
/// </summary>
|
||||
public static async ValueTask IterParallel<T1, T2>(this IEnumerable<(T1, T2)> enumerable, Func<T1, T2, CancellationToken, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(async (t, cancellationToken) => await action(t.Item1, t.Item2, cancellationToken), cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each element and filters out <seealso cref="Option.None"/> values.
|
||||
/// </summary>
|
||||
public static IEnumerable<T2> Choose<T, T2>(this IEnumerable<T> enumerable, Func<T, Option<T2>> f)
|
||||
{
|
||||
var enumerableM = enumerable.AsEnumerableM();
|
||||
|
||||
return EnumerableMExtensions.Choose(enumerableM, f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each element of <paramref name="enumerable"/> and returns the first Option of <typeparamref name="T2"/>
|
||||
/// that is Some. If all options are None, returns a None.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <param name="enumerable"></param>
|
||||
/// <param name="f"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static Option<T2> Pick<T, T2>(this IEnumerable<T> enumerable, Func<T, Option<T2>> f) =>
|
||||
enumerable.Select(f)
|
||||
.Where(option => option.IsSome)
|
||||
.DefaultIfEmpty(Option<T2>.None)
|
||||
.First();
|
||||
public static async ValueTask<Option<T2>> Pick<T, T2>(this IEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask<Option<T2>>> f, CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
var option = await f(item, cancellationToken);
|
||||
|
||||
public static FrozenDictionary<TKey, TValue> ToFrozenDictionary<TKey, TValue>(this IEnumerable<(TKey Key, TValue Value)> enumerable, IEqualityComparer<TKey>? comparer = default) where TKey : notnull =>
|
||||
enumerable.ToFrozenDictionary(x => x.Key, x => x.Value, comparer);
|
||||
if (option.IsSome)
|
||||
{
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
public static FrozenDictionary<TKey, TValue> ToFrozenDictionary<TKey, TValue, TComparison>(this IEnumerable<(TKey Key, TValue Value)> enumerable, Func<TKey, TComparison> comparer) where TKey : notnull =>
|
||||
enumerable.ToFrozenDictionary(x => x.Key, x => x.Value, EqualityComparerBuilder.For<TKey>().EquateBy(comparer));
|
||||
return Option<T2>.None;
|
||||
}
|
||||
|
||||
public static FrozenSet<T> ToFrozenSet<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> keySelector) =>
|
||||
enumerable.ToFrozenSet(EqualityComparerBuilder.For<T>().EquateBy(keySelector));
|
||||
/// <summary>
|
||||
/// Returns the first item in the enumerable. If the enumerable is empty, returns <seealso cref="Option.None"/>.
|
||||
/// </summary>
|
||||
public static Option<T> HeadOrNone<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
var m = enumerable.AsEnumerableM();
|
||||
|
||||
return FoldableExtensions.Head(m);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the last item in the enumerable. If the enumerable is empty, returns <seealso cref="Option.None"/>.
|
||||
/// </summary>
|
||||
public static Option<T> LastOrNone<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
var m = enumerable.AsEnumerableM();
|
||||
|
||||
return FoldableExtensions.Last(m);
|
||||
}
|
||||
|
||||
public static FrozenSet<T> ToFrozenSet<T, TKey>(this IEnumerable<T> enumerable, Func<T, TKey> keySelector)
|
||||
{
|
||||
var comparer = EqualityComparerBuilder.For<T>().EquateBy(keySelector);
|
||||
|
||||
return enumerable.ToFrozenSet(comparer);
|
||||
}
|
||||
|
||||
public static FrozenDictionary<TKey, TValue> ToFrozenDictionary<TKey, TValue>(this IEnumerable<(TKey, TValue)> enumerable, IEqualityComparer<TKey>? comparer = default) where TKey : notnull =>
|
||||
enumerable.ToFrozenDictionary(kvp => kvp.Item1, kvp => kvp.Item2, comparer);
|
||||
}
|
||||
|
||||
public static class IAsyncEnumerableExtensions
|
||||
{
|
||||
public static IAsyncEnumerable<T> Do<T>(this IAsyncEnumerable<T> enumerable, Func<T, ValueTask> action) =>
|
||||
enumerable.SelectAwait(async t =>
|
||||
{
|
||||
await action(t);
|
||||
return t;
|
||||
});
|
||||
|
||||
public static IAsyncEnumerable<T> Do<T>(this IAsyncEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask> action) =>
|
||||
enumerable.SelectAwaitWithCancellation(async (t, cancellationToken) =>
|
||||
{
|
||||
await action(t, cancellationToken);
|
||||
return t;
|
||||
});
|
||||
|
||||
public static async ValueTask Iter<T>(this IAsyncEnumerable<T> enumerable, Action<T> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(async (t, _) =>
|
||||
{
|
||||
action(t);
|
||||
await ValueTask.CompletedTask;
|
||||
}, maxDegreeOfParallelism: 1, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed sequentially. The function returns after all actions have executed.
|
||||
/// </summary>
|
||||
public static async ValueTask Iter<T>(this IAsyncEnumerable<T> enumerable, Func<T, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.Iter(async (t, _) => await action(t), cancellationToken);
|
||||
await enumerable.Iter(async (t, cancellationToken) => await action(t), cancellationToken);
|
||||
|
||||
public static async ValueTask Iter<T>(this IAsyncEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(action, maxDegreeOfParallelism: 1, cancellationToken);
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed sequentially. The function returns after all actions have executed.
|
||||
/// </summary>
|
||||
public static async ValueTask Iter<T>(this IAsyncEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask> action, CancellationToken cancellationToken)
|
||||
{
|
||||
await foreach (var item in enumerable.WithCancellation(cancellationToken))
|
||||
{
|
||||
await action(item, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IAsyncEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed in parallel. The function will wait for all actions to complete before returning.
|
||||
/// </summary>
|
||||
public static async ValueTask IterParallel<T>(this IAsyncEnumerable<T> enumerable, Func<T, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(async (t, _) => await action(t), maxDegreeOfParallelism: -1, cancellationToken);
|
||||
await enumerable.IterParallel(async (t, _) => await action(t), maxDegreeOfParallelism: -1, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IAsyncEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed in parallel. The function will wait for all actions to complete before returning.
|
||||
/// </summary>
|
||||
public static async ValueTask IterParallel<T>(this IAsyncEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(action, maxDegreeOfParallelism: -1, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over an <seealso cref="IAsyncEnumerable{T}"/> and executes <paramref name="action"/> for each element.
|
||||
/// <paramref name="maxDegreeOfParallelism"/> controls the maximum number of parallel actions. The function will wait for all actions to complete before returning.
|
||||
/// </summary>
|
||||
public static async ValueTask IterParallel<T>(this IAsyncEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask> action, int maxDegreeOfParallelism, CancellationToken cancellationToken)
|
||||
{
|
||||
var options = new ParallelOptions
|
||||
|
@ -111,133 +179,120 @@ public static class IAsyncEnumerableExtensions
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each element of <paramref name="enumerable"/> and filters out cases where the resulting Option of <typeparamref name="T2"/> is None.
|
||||
/// Iterates over an <seealso cref="IAsyncEnumerable"/> and executes <paramref name="action"/> for each element.
|
||||
/// Each action is executed in parallel. The function will wait for all actions to complete before returning.
|
||||
/// </summary>
|
||||
public static async ValueTask IterParallel<T1, T2>(this IAsyncEnumerable<(T1, T2)> enumerable, Func<T1, T2, CancellationToken, ValueTask> action, CancellationToken cancellationToken) =>
|
||||
await enumerable.IterParallel(async (t, cancellationToken) => await action(t.Item1, t.Item2, cancellationToken), cancellationToken);
|
||||
|
||||
public static async ValueTask<FrozenSet<T>> ToFrozenSet<T>(this IAsyncEnumerable<T> enumerable, CancellationToken cancellationToken, IEqualityComparer<T>? comparer = default)
|
||||
{
|
||||
var items = await enumerable.ToListAsync(cancellationToken);
|
||||
|
||||
return items.ToFrozenSet(comparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each element and filters out <seealso cref="Option.None"/> values.
|
||||
/// </summary>
|
||||
public static IAsyncEnumerable<T2> Choose<T, T2>(this IAsyncEnumerable<T> enumerable, Func<T, Option<T2>> f) =>
|
||||
enumerable.Choose(async t => await f(t).AsValueTask());
|
||||
enumerable.Choose(async (t, cancellationToken) => await ValueTask.FromResult(f(t)));
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each element of <paramref name="enumerable"/> and filters out cases where the resulting Option of <typeparamref name="T2"/> is None.
|
||||
/// Applies <paramref name="f"/> to each element and filters out <seealso cref="Option.None"/> values.
|
||||
/// </summary>
|
||||
public static IAsyncEnumerable<T2> Choose<T, T2>(this IAsyncEnumerable<T> enumerable, Func<T, ValueTask<Option<T2>>> f) =>
|
||||
enumerable.Choose((t, cancellationToken) => f(t));
|
||||
enumerable.Choose(async (t, cancellationToken) => await f(t));
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each element of <paramref name="enumerable"/> and filters out cases where the resulting Option of <typeparamref name="T2"/> is None.
|
||||
/// Applies <paramref name="f"/> to each element and filters out <seealso cref="Option.None"/> values.
|
||||
/// </summary>
|
||||
public static IAsyncEnumerable<T2> Choose<T, T2>(this IAsyncEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask<Option<T2>>> f) =>
|
||||
enumerable.SelectAwaitWithCancellation(f)
|
||||
.Where(option => option.IsSome)
|
||||
.Select(option => option.ValueUnsafe());
|
||||
.Select(option => option.ValueUnsafe()!);
|
||||
|
||||
public static async ValueTask<Option<T>> HeadOrNone<T>(this IAsyncEnumerable<T> enumerable, CancellationToken cancellationToken) =>
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static async ValueTask<Option<T>> FirstOrNone<T>(this IAsyncEnumerable<T> enumerable, CancellationToken cancellationToken) =>
|
||||
await enumerable.Select(Option<T>.Some)
|
||||
.DefaultIfEmpty(Option<T>.None)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
.FirstAsync(cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each element of <paramref name="enumerable"/> and returns the first Option of <typeparamref name="T2"/>
|
||||
/// that is Some. If all options are None, returns a None.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <param name="enumerable"></param>
|
||||
/// <param name="f"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static async ValueTask<Option<T2>> Pick<T, T2>(this IAsyncEnumerable<T> enumerable, Func<T, ValueTask<Option<T2>>> f, CancellationToken cancellationToken) =>
|
||||
await enumerable.SelectAwait(f)
|
||||
.Where(option => option.IsSome)
|
||||
.DefaultIfEmpty(Option<T2>.None)
|
||||
.FirstAsync(cancellationToken);
|
||||
public static async ValueTask<Option<T2>> Pick<T, T2>(this IAsyncEnumerable<T> enumerable, Func<T, CancellationToken, ValueTask<Option<T2>>> f, CancellationToken cancellationToken) =>
|
||||
await enumerable.Choose(f)
|
||||
.FirstOrNone(cancellationToken);
|
||||
|
||||
public static async IAsyncEnumerable<TResult> FullJoin<T1, T2, TKey, TResult>(this IAsyncEnumerable<T1> first,
|
||||
IAsyncEnumerable<T2> second,
|
||||
Func<T1, ValueTask<TKey>> firstKeySelector,
|
||||
Func<T2, ValueTask<TKey>> secondKeySelector,
|
||||
Func<T1, ValueTask<TResult>> firstResultSelector,
|
||||
Func<T2, ValueTask<TResult>> secondResultSelector,
|
||||
Func<T1, T2, ValueTask<TResult>> bothResultSelector,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
public static async ValueTask<FrozenDictionary<TKey, TValue>> ToFrozenDictionary<TKey, TValue>(this IAsyncEnumerable<(TKey, TValue)> enumerable, CancellationToken cancellationToken, IEqualityComparer<TKey>? comparer = default) where TKey : notnull
|
||||
{
|
||||
var secondLookup = await second.ToLookupAwaitAsync(secondKeySelector, cancellationToken);
|
||||
var keys = new System.Collections.Generic.HashSet<TKey>();
|
||||
var array = await enumerable.ToArrayAsync(cancellationToken);
|
||||
|
||||
await foreach (var firstItem in first.WithCancellation(cancellationToken))
|
||||
{
|
||||
var firstKey = await firstKeySelector(firstItem);
|
||||
keys.Add(firstKey);
|
||||
|
||||
if (secondLookup.Contains(firstKey))
|
||||
{
|
||||
var secondItems = secondLookup[firstKey];
|
||||
|
||||
foreach (var secondItem in secondItems)
|
||||
{
|
||||
yield return await bothResultSelector(firstItem, secondItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return await firstResultSelector(firstItem);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var group in secondLookup)
|
||||
{
|
||||
if (keys.Contains(group.Key) is false)
|
||||
{
|
||||
foreach (var secondItem in group)
|
||||
{
|
||||
yield return await secondResultSelector(secondItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return array.ToFrozenDictionary(comparer);
|
||||
}
|
||||
}
|
||||
|
||||
public static async ValueTask<FrozenSet<T>> ToFrozenSet<T>(this IAsyncEnumerable<T> enumerable, CancellationToken cancellationToken, IEqualityComparer<T>? comparer = null)
|
||||
{
|
||||
var result = await enumerable.ToArrayAsync(cancellationToken);
|
||||
public static class KeyValuePairExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each value and filters out <seealso cref="Option.None"/> values.
|
||||
/// </summary>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue2>> ChooseValues<TKey, TValue, TValue2>(this IEnumerable<KeyValuePair<TKey, TValue>> keyValuePairs, Func<TValue, Option<TValue2>> f) =>
|
||||
keyValuePairs.Choose(kvp => from value2 in f(kvp.Value)
|
||||
select KeyValuePair.Create(kvp.Key, value2));
|
||||
|
||||
return result.ToFrozenSet(comparer);
|
||||
}
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each key and filters out <seealso cref="Option.None"/> keys.
|
||||
/// </summary>
|
||||
public static IEnumerable<KeyValuePair<TKey2, TValue>> ChooseKeys<TKey, TKey2, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> keyValuePairs, Func<TKey, Option<TKey2>> f) =>
|
||||
keyValuePairs.Choose(kvp => from key2 in f(kvp.Key)
|
||||
select KeyValuePair.Create(key2, kvp.Value));
|
||||
|
||||
public static async ValueTask<FrozenDictionary<TKey, TValue>> ToFrozenDictionary<TKey, TValue>(this IAsyncEnumerable<(TKey Key, TValue Value)> enumerable, CancellationToken cancellationToken) where TKey : notnull
|
||||
{
|
||||
var list = await enumerable.ToArrayAsync(cancellationToken);
|
||||
/// <summary>
|
||||
/// Creates a new key value pair whose value is <paramref name="f"/>(<paramref name="keyValuePair"/>.Value).
|
||||
/// </summary>
|
||||
public static KeyValuePair<TKey, TValue2> MapValue<TKey, TValue, TValue2>(this KeyValuePair<TKey, TValue> keyValuePair, Func<TValue, TValue2> f) =>
|
||||
KeyValuePair.Create(keyValuePair.Key, f(keyValuePair.Value));
|
||||
|
||||
return list.ToFrozenDictionary();
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a new key value pair whose key is <paramref name="f"/>(<paramref name="keyValuePair"/>.Key).
|
||||
/// </summary>
|
||||
public static KeyValuePair<TKey2, TValue> MapKey<TKey, TKey2, TValue>(this KeyValuePair<TKey, TValue> keyValuePair, Func<TKey, TKey2> f) =>
|
||||
KeyValuePair.Create(f(keyValuePair.Key), keyValuePair.Value);
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each key
|
||||
/// </summary>
|
||||
public static IEnumerable<KeyValuePair<TKey2, TValue>> MapKey<TKey, TKey2, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> enumerable, Func<TKey, TKey2> f) =>
|
||||
enumerable.Select(kvp => kvp.MapKey(f));
|
||||
|
||||
/// <summary>
|
||||
/// Applies <paramref name="f"/> to each value
|
||||
/// </summary>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue2>> MapValue<TKey, TValue, TValue2>(this IEnumerable<KeyValuePair<TKey, TValue>> enumerable, Func<TValue, TValue2> f) =>
|
||||
enumerable.Select(kvp => kvp.MapValue(f));
|
||||
|
||||
/// <summary>
|
||||
/// Removes keys where the predicate is false
|
||||
/// </summary>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue>> WhereKey<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> enumerable, Func<TKey, bool> predicate) =>
|
||||
enumerable.Where(kvp => predicate(kvp.Key));
|
||||
|
||||
/// <summary>
|
||||
/// Removes values where the predicate is false
|
||||
/// </summary>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue>> WhereValue<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> enumerable, Func<TValue, bool> predicate) =>
|
||||
enumerable.Where(kvp => predicate(kvp.Value));
|
||||
}
|
||||
|
||||
public static class DictionaryExtensions
|
||||
{
|
||||
public static Option<TValue> Find<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key) where TKey : notnull =>
|
||||
public static Option<TValue> Find<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key) =>
|
||||
dictionary.TryGetValue(key, out var value)
|
||||
? value
|
||||
? Option<TValue>.Some(value)
|
||||
: Option<TValue>.None;
|
||||
|
||||
public static ImmutableDictionary<TKey, TValue> WhereKey<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> dictionary, Func<TKey, bool> predicate) where TKey : notnull =>
|
||||
dictionary.Where(kvp => predicate(kvp.Key))
|
||||
.ToImmutableDictionary();
|
||||
|
||||
public static ImmutableDictionary<TKey, TValue> WhereValue<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> dictionary, Func<TValue, bool> predicate) where TKey : notnull =>
|
||||
dictionary.Where(kvp => predicate(kvp.Value))
|
||||
.ToImmutableDictionary();
|
||||
|
||||
public static ImmutableDictionary<TKey2, TValue> MapKey<TKey1, TKey2, TValue>(this IEnumerable<KeyValuePair<TKey1, TValue>> dictionary, Func<TKey1, TKey2> f) where TKey2 : notnull =>
|
||||
dictionary.ToImmutableDictionary(kvp => f(kvp.Key), kvp => kvp.Value);
|
||||
|
||||
public static ImmutableDictionary<TKey, TValue2> MapValue<TKey, TValue1, TValue2>(this IEnumerable<KeyValuePair<TKey, TValue1>> dictionary, Func<TValue1, TValue2> f) where TKey : notnull =>
|
||||
dictionary.ToImmutableDictionary(kvp => kvp.Key, kvp => f(kvp.Value));
|
||||
|
||||
public static ImmutableDictionary<TKey2, TValue> ChooseKey<TKey, TKey2, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> dictionary, Func<TKey, Option<TKey2>> f) where TKey2 : notnull =>
|
||||
dictionary.Choose(kvp => from key2 in f(kvp.Key)
|
||||
select KeyValuePair.Create(key2, kvp.Value))
|
||||
.ToImmutableDictionary();
|
||||
|
||||
public static ImmutableDictionary<TKey, TValue2> ChooseValue<TKey, TValue1, TValue2>(this IEnumerable<KeyValuePair<TKey, TValue1>> dictionary, Func<TValue1, Option<TValue2>> f) where TKey : notnull =>
|
||||
dictionary.Choose(kvp => from value2 in f(kvp.Value)
|
||||
select KeyValuePair.Create(kvp.Key, value2))
|
||||
.ToImmutableDictionary();
|
||||
}
|
|
@ -191,17 +191,6 @@ public static class GatewayModule
|
|||
return content.ToObjectFromJson<GatewayDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<GatewayDto>> TryGetDto(this GatewayUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<GatewayDto>())
|
||||
.Match(Option<GatewayDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<GatewayDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this GatewayUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -169,17 +169,6 @@ public static class GroupModule
|
|||
return content.ToObjectFromJson<GroupDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<GroupDto>> TryGetDto(this GroupUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<GroupDto>())
|
||||
.Match(Option<GroupDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<GroupDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this GroupUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryDeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public delegate ValueTask RunApplication(CancellationToken cancellationToken);
|
||||
|
||||
public static class HostingModule
|
||||
{
|
||||
/// <param name="applicationName">Will be used to set the logger name and the OpenTelemetry activity source name.</param>
|
||||
/// <param name="configureRunApplication">Delegate that adds <see cref="common.RunApplication" /> to the builder services.</param>
|
||||
/// <returns></returns>
|
||||
public static async ValueTask RunHost(string[] arguments, string applicationName, Action<IHostApplicationBuilder> configureRunApplication)
|
||||
{
|
||||
using var host = GetHost(arguments, applicationName, configureRunApplication);
|
||||
await StartHost(host);
|
||||
await RunApplication(host);
|
||||
}
|
||||
|
||||
private static IHost GetHost(string[] arguments, string applicationName, Action<IHostApplicationBuilder> configureRunApplication)
|
||||
{
|
||||
var builder = GetBuilder(arguments, applicationName, configureRunApplication);
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
private static HostApplicationBuilder GetBuilder(string[] arguments, string applicationName, Action<IHostApplicationBuilder> configureRunApplication)
|
||||
{
|
||||
var builder = Host.CreateApplicationBuilder(arguments);
|
||||
ConfigureBuilder(builder, applicationName, configureRunApplication);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static void ConfigureBuilder(HostApplicationBuilder builder, string applicationName, Action<IHostApplicationBuilder> configureRunApplication)
|
||||
{
|
||||
ConfigureConfiguration(builder);
|
||||
OpenTelemetryModule.Configure(builder, applicationName);
|
||||
ConfigureLogging(builder, applicationName);
|
||||
configureRunApplication(builder);
|
||||
}
|
||||
|
||||
private static void ConfigureConfiguration(HostApplicationBuilder builder)
|
||||
{
|
||||
if (Assembly.GetEntryAssembly() is Assembly entryAssembly)
|
||||
{
|
||||
builder.Configuration.AddUserSecretsWithLowestPriority(entryAssembly);
|
||||
}
|
||||
|
||||
builder.Configuration
|
||||
.TryGetValue("CONFIGURATION_YAML_PATH")
|
||||
.Iter(path => builder.Configuration.AddYamlFile(path));
|
||||
}
|
||||
|
||||
private static void ConfigureLogging(HostApplicationBuilder builder, string applicationName)
|
||||
{
|
||||
builder.Services.TryAddSingleton(provider => GetCommonLogger(provider, applicationName));
|
||||
}
|
||||
|
||||
private static ILogger GetCommonLogger(IServiceProvider provider, string applicationName)
|
||||
{
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
return loggerFactory.CreateLogger(applicationName);
|
||||
}
|
||||
|
||||
private static async ValueTask StartHost(IHost host)
|
||||
{
|
||||
var applicationLifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
|
||||
var cancellationToken = applicationLifetime.ApplicationStopping;
|
||||
await host.StartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the delegate <see cref="common.RunApplication"/> from the host's services and runs it.
|
||||
/// </summary>
|
||||
private static async ValueTask RunApplication(IHost host)
|
||||
{
|
||||
var applicationLifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
|
||||
var cancellationToken = applicationLifetime.ApplicationStopping;
|
||||
|
||||
try
|
||||
{
|
||||
var runApplication = host.Services.GetRequiredService<RunApplication>();
|
||||
await runApplication(cancellationToken);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
var logger = host.Services.GetRequiredService<ILogger>();
|
||||
logger.LogCritical(exception, "Application failed.");
|
||||
Environment.ExitCode = -1;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
applicationLifetime.StopApplication();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,13 +26,25 @@ public static class HttpPipelineExtensions
|
|||
{
|
||||
var either = await pipeline.TryGetContent(uri, cancellationToken);
|
||||
|
||||
return either.IfLeft(response =>
|
||||
return either.IfLeftThrow(uri);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the response content. If the status code is <see cref="HttpStatusCode.NotFound"/>, returns <see cref="Option.None"/>.
|
||||
/// </summary>
|
||||
public static async ValueTask<Option<BinaryData>> GetContentOption(this HttpPipeline pipeline, Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri, cancellationToken);
|
||||
|
||||
return either.Match(response =>
|
||||
{
|
||||
using (response)
|
||||
{
|
||||
throw response.ToHttpRequestException(uri);
|
||||
return response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<BinaryData>.None
|
||||
: throw response.ToHttpRequestException(uri);
|
||||
}
|
||||
});
|
||||
}, Option<BinaryData>.Some);
|
||||
}
|
||||
|
||||
public static async ValueTask<Either<Response, BinaryData>> TryGetContent(this HttpPipeline pipeline, Uri uri, CancellationToken cancellationToken)
|
||||
|
@ -57,6 +69,15 @@ public static class HttpPipelineExtensions
|
|||
public static HttpRequestException ToHttpRequestException(this Response response, Uri requestUri) =>
|
||||
new(message: $"HTTP request to URI {requestUri} failed with status code {response.Status}. Content is '{response.Content}'.", inner: null, statusCode: (HttpStatusCode)response.Status);
|
||||
|
||||
private static T IfLeftThrow<T>(this Either<Response, T> either, Uri requestUri) =>
|
||||
either.IfLeft(response =>
|
||||
{
|
||||
using (response)
|
||||
{
|
||||
throw response.ToHttpRequestException(requestUri);
|
||||
}
|
||||
});
|
||||
|
||||
public static async IAsyncEnumerable<JsonObject> ListJsonObjects(this HttpPipeline pipeline, Uri uri, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
Uri? nextLink = uri;
|
||||
|
@ -66,8 +87,8 @@ public static class HttpPipelineExtensions
|
|||
var responseJson = await pipeline.GetJsonObject(nextLink, cancellationToken);
|
||||
|
||||
var values = responseJson.TryGetJsonArrayProperty("value")
|
||||
.IfLeft(() => new JsonArray())
|
||||
.GetJsonObjects();
|
||||
.IfLeft(() => [])
|
||||
.PickJsonObjects();
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
|
@ -83,13 +104,17 @@ public static class HttpPipelineExtensions
|
|||
{
|
||||
var either = await pipeline.TryGetJsonObject(uri, cancellationToken);
|
||||
|
||||
return either.IfLeft(response =>
|
||||
{
|
||||
using (response)
|
||||
{
|
||||
throw response.ToHttpRequestException(uri);
|
||||
}
|
||||
});
|
||||
return either.IfLeftThrow(uri);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the response content as a JSON object. If the status code is <see cref="HttpStatusCode.NotFound"/>, returns <see cref="Option.None"/>.
|
||||
/// </summary>
|
||||
public static async ValueTask<Option<JsonObject>> GetJsonObjectOption(this HttpPipeline pipeline, Uri uri, CancellationToken cancellationToken)
|
||||
{
|
||||
var option = await pipeline.GetContentOption(uri, cancellationToken);
|
||||
|
||||
return option.Map(content => content.ToObjectFromJson<JsonObject>());
|
||||
}
|
||||
|
||||
public static async ValueTask<Either<Response, JsonObject>> TryGetJsonObject(this HttpPipeline pipeline, Uri uri, CancellationToken cancellationToken)
|
||||
|
@ -103,16 +128,7 @@ public static class HttpPipelineExtensions
|
|||
{
|
||||
var either = await pipeline.TryDeleteResource(uri, waitForCompletion, cancellationToken);
|
||||
|
||||
either.IfLeft(response =>
|
||||
{
|
||||
using (response)
|
||||
{
|
||||
if (response.Status is not (int)HttpStatusCode.NotFound)
|
||||
{
|
||||
throw response.ToHttpRequestException(uri);
|
||||
}
|
||||
}
|
||||
});
|
||||
either.IfLeftThrow(uri);
|
||||
}
|
||||
|
||||
public static async ValueTask<Either<Response, Unit>> TryDeleteResource(this HttpPipeline pipeline, Uri uri, bool waitForCompletion, CancellationToken cancellationToken)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using LanguageExt;
|
||||
using LanguageExt.UnsafeValueAccess;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
@ -7,98 +6,63 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public static class JsonArrayExtensions
|
||||
public static class JsonValueExtensions
|
||||
{
|
||||
public static JsonArray ToJsonArray(this IEnumerable<JsonNode?> nodes) =>
|
||||
nodes.Aggregate(new JsonArray(),
|
||||
(array, node) =>
|
||||
{
|
||||
array.Add(node);
|
||||
return array;
|
||||
});
|
||||
public static Either<string, string> TryAsString(this JsonValue? jsonValue) =>
|
||||
jsonValue is null
|
||||
? Either<string, string>.Left("JSON value is null.")
|
||||
: jsonValue.TryGetValue<string>(out var stringValue)
|
||||
? Either<string, string>.Right(stringValue)
|
||||
: Either<string, string>.Left("JSON value is not a string.");
|
||||
|
||||
public static ValueTask<JsonArray> ToJsonArray(this IAsyncEnumerable<JsonNode?> nodes, CancellationToken cancellationToken) =>
|
||||
nodes.AggregateAsync(new JsonArray(),
|
||||
(array, node) =>
|
||||
{
|
||||
array.Add(node);
|
||||
return array;
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
public static ImmutableArray<JsonObject> GetJsonObjects(this JsonArray jsonArray) =>
|
||||
jsonArray.Choose(node => node.TryAsJsonObject())
|
||||
.ToImmutableArray();
|
||||
|
||||
public static ImmutableArray<JsonArray> GetJsonArrays(this JsonArray jsonArray) =>
|
||||
jsonArray.Choose(node => node.TryAsJsonArray())
|
||||
.ToImmutableArray();
|
||||
|
||||
public static ImmutableArray<JsonValue> GetJsonValues(this JsonArray jsonArray) =>
|
||||
jsonArray.Choose(node => node.TryAsJsonValue())
|
||||
.ToImmutableArray();
|
||||
|
||||
public static ImmutableArray<string> GetNonEmptyOrWhitespaceStrings(this JsonArray jsonArray) =>
|
||||
jsonArray.Choose(node => node.TryAsString())
|
||||
.Where(value => !string.IsNullOrWhiteSpace(value))
|
||||
.ToImmutableArray();
|
||||
public static Either<string, Uri> TryAsAbsoluteUri(this JsonValue? jsonValue) =>
|
||||
jsonValue.TryAsString()
|
||||
.Bind(uriString => Uri.TryCreate(uriString, UriKind.Absolute, out var uri)
|
||||
? Either<string, Uri>.Right(uri)
|
||||
: $"JSON value '{uriString}' is not a valid absolute URI.");
|
||||
}
|
||||
|
||||
public static class JsonNodeExtensions
|
||||
{
|
||||
public static JsonNodeOptions Options { get; } = new() { PropertyNameCaseInsensitive = true };
|
||||
|
||||
public static Option<JsonObject> TryAsJsonObject(this JsonNode? node) =>
|
||||
public static Either<string, JsonObject> TryAsJsonObject(this JsonNode? node) =>
|
||||
node is JsonObject jsonObject
|
||||
? jsonObject
|
||||
: Option<JsonObject>.None;
|
||||
? jsonObject
|
||||
: "Node is not a JSON object.";
|
||||
|
||||
public static Option<JsonArray> TryAsJsonArray(this JsonNode? node) =>
|
||||
public static Either<string, JsonArray> TryAsJsonArray(this JsonNode? node) =>
|
||||
node is JsonArray jsonArray
|
||||
? jsonArray
|
||||
: Option<JsonArray>.None;
|
||||
? jsonArray
|
||||
: "Node is not a JSON array.";
|
||||
|
||||
public static Option<JsonValue> TryAsJsonValue(this JsonNode? node) =>
|
||||
public static Either<string, JsonValue> TryAsJsonValue(this JsonNode? node) =>
|
||||
node is JsonValue jsonValue
|
||||
? jsonValue
|
||||
: Option<JsonValue>.None;
|
||||
? jsonValue
|
||||
: "Node is not a JSON value.";
|
||||
|
||||
public static Option<string> TryAsString(this JsonNode? node) =>
|
||||
public static Either<string, string> TryAsString(this JsonNode? node) =>
|
||||
node.TryAsJsonValue()
|
||||
.Bind(JsonValueExtensions.TryAsString);
|
||||
.Bind(jsonValue => jsonValue.TryAsString());
|
||||
|
||||
public static Option<Guid> TryAsGuid(this JsonNode? node) =>
|
||||
public static Either<string, Uri> TryAsAbsoluteUri(this JsonNode? node) =>
|
||||
node.TryAsJsonValue()
|
||||
.Bind(JsonValueExtensions.TryAsGuid);
|
||||
.Bind(jsonValue => jsonValue.TryAsAbsoluteUri());
|
||||
}
|
||||
|
||||
public static Option<Uri> TryAsAbsoluteUri(this JsonNode? node) =>
|
||||
node.TryAsJsonValue()
|
||||
.Bind(JsonValueExtensions.TryAsAbsoluteUri);
|
||||
public static class JsonArrayExtensions
|
||||
{
|
||||
public static ImmutableArray<JsonObject> PickJsonObjects(this JsonArray jsonArray) =>
|
||||
jsonArray.Choose(node => node.TryAsJsonObject().ToOption())
|
||||
.ToImmutableArray();
|
||||
|
||||
public static Option<DateTimeOffset> TryAsDateTimeOffset(this JsonNode? node) =>
|
||||
node.TryAsJsonValue()
|
||||
.Bind(JsonValueExtensions.TryAsDateTimeOffset);
|
||||
public static ImmutableArray<string> PickStrings(this JsonArray jsonArray) =>
|
||||
jsonArray.Choose(node => node.TryAsString().ToOption())
|
||||
.ToImmutableArray();
|
||||
|
||||
public static Option<DateTime> TryAsDateTime(this JsonNode? node) =>
|
||||
node.TryAsJsonValue()
|
||||
.Bind(JsonValueExtensions.TryAsDateTime);
|
||||
|
||||
public static Option<int> TryAsInt(this JsonNode? node) =>
|
||||
node.TryAsJsonValue()
|
||||
.Bind(JsonValueExtensions.TryAsInt);
|
||||
|
||||
public static Option<double> TryAsDouble(this JsonNode? node) =>
|
||||
node.TryAsJsonValue()
|
||||
.Bind(JsonValueExtensions.TryAsDouble);
|
||||
|
||||
public static Option<bool> TryAsBool(this JsonNode? node) =>
|
||||
node.TryAsJsonValue()
|
||||
.Bind(JsonValueExtensions.TryAsBool);
|
||||
public static JsonArray ToJsonArray(this IEnumerable<JsonNode> nodes) =>
|
||||
new(nodes.ToArray());
|
||||
}
|
||||
|
||||
public static class JsonObjectExtensions
|
||||
|
@ -108,169 +72,76 @@ public static class JsonObjectExtensions
|
|||
WriteIndented = true
|
||||
};
|
||||
|
||||
public static JsonNode GetProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
public static JsonNode GetProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Option<JsonNode> GetOptionalProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.ToOption();
|
||||
.IfLeftThrow();
|
||||
|
||||
public static Either<string, JsonNode> TryGetProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject is null
|
||||
? "JSON object is null."
|
||||
: jsonObject.TryGetPropertyValue(propertyName, out var node)
|
||||
? node is null
|
||||
? $"Property '{propertyName}' is null."
|
||||
: Either<string, JsonNode>.Right(node)
|
||||
: $"Property '{propertyName}' is missing.";
|
||||
? "JSON object is null."
|
||||
: jsonObject.TryGetPropertyValue(propertyName, out var property)
|
||||
? property is null
|
||||
? $"Property '{propertyName}' is null."
|
||||
: property
|
||||
: $"Property '{propertyName}' is missing.";
|
||||
|
||||
public static JsonObject GetJsonObjectProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
private static T IfLeftThrow<T>(this Either<string, T> either) =>
|
||||
either.IfLeft(error => throw new JsonException(error));
|
||||
|
||||
public static JsonObject GetJsonObjectProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetJsonObjectProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
.IfLeftThrow();
|
||||
|
||||
public static Either<string, JsonObject> TryGetJsonObjectProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsJsonObject(propertyName));
|
||||
.Bind(JsonNodeExtensions.TryAsJsonObject)
|
||||
.BindPropertyError(propertyName);
|
||||
|
||||
private static Either<string, JsonObject> TryAsJsonObject(this JsonNode node, string propertyName) =>
|
||||
node.TryAsJsonObject()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a JSON object.");
|
||||
|
||||
public static JsonArray GetJsonArrayProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetJsonArrayProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
private static Either<string, T> BindPropertyError<T>(this Either<string, T> either, string propertyName) =>
|
||||
either.MapLeft(error => $"Property '{propertyName}' is invalid. {error}");
|
||||
|
||||
public static Either<string, JsonArray> TryGetJsonArrayProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsJsonArray(propertyName));
|
||||
|
||||
private static Either<string, JsonArray> TryAsJsonArray(this JsonNode node, string propertyName) =>
|
||||
node.TryAsJsonArray()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a JSON array.");
|
||||
|
||||
public static JsonValue GetJsonValueProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetJsonValueProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, JsonValue> TryGetJsonValueProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsJsonValue(propertyName));
|
||||
|
||||
private static Either<string, JsonValue> TryAsJsonValue(this JsonNode node, string propertyName) =>
|
||||
node.TryAsJsonValue()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a JSON value.");
|
||||
|
||||
public static string GetStringProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetStringProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, string> TryGetStringProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsString(propertyName));
|
||||
|
||||
private static Either<string, string> TryAsString(this JsonNode node, string propertyName) =>
|
||||
node.TryAsString()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a string.");
|
||||
|
||||
public static string GetNonEmptyOrWhiteSpaceStringProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetNonEmptyOrWhiteSpaceStringProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, string> TryGetNonEmptyOrWhiteSpaceStringProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetStringProperty(propertyName)
|
||||
.Bind(value => string.IsNullOrWhiteSpace(value)
|
||||
? Either<string, string>.Left($"Property '{propertyName}' is empty or whitespace.")
|
||||
: Either<string, string>.Right(value));
|
||||
|
||||
public static Guid GetGuidProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetGuidProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, Guid> TryGetGuidProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsGuid(propertyName));
|
||||
|
||||
private static Either<string, Guid> TryAsGuid(this JsonNode node, string propertyName) =>
|
||||
node.TryAsGuid()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a GUID.");
|
||||
.Bind(JsonNodeExtensions.TryAsJsonArray)
|
||||
.BindPropertyError(propertyName);
|
||||
|
||||
public static Uri GetAbsoluteUriProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetAbsoluteUriProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
.IfLeftThrow();
|
||||
|
||||
public static Either<string, Uri> TryGetAbsoluteUriProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsAbsoluteUri(propertyName));
|
||||
.Bind(JsonNodeExtensions.TryAsAbsoluteUri)
|
||||
.BindPropertyError(propertyName);
|
||||
|
||||
public static DateTimeOffset GetDateTimeOffsetProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetDateTimeOffsetProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, DateTimeOffset> TryGetDateTimeOffsetProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
public static Either<string, string> TryGetStringProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsDateTimeOffset(propertyName));
|
||||
.Bind(JsonNodeExtensions.TryAsString)
|
||||
.BindPropertyError(propertyName);
|
||||
|
||||
private static Either<string, DateTimeOffset> TryAsDateTimeOffset(this JsonNode node, string propertyName) =>
|
||||
node.TryAsDateTimeOffset()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a valid DateTimeOffset.");
|
||||
public static string GetNonEmptyOrWhiteSpaceStringProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetNonEmptyOrWhiteSpaceStringProperty(propertyName)
|
||||
.IfLeftThrow();
|
||||
|
||||
public static DateTime GetDateTimeProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetDateTimeProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, DateTime> TryGetDateTimeProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
public static Either<string, string> TryGetNonEmptyOrWhiteSpaceStringProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsDateTime(propertyName));
|
||||
.Bind(JsonNodeExtensions.TryAsString)
|
||||
.Bind(value => string.IsNullOrWhiteSpace(value)
|
||||
? Either<string, string>.Left($"Property '{propertyName}' is empty or whitespace.")
|
||||
: Either<string, string>.Right(value))
|
||||
.BindPropertyError(propertyName);
|
||||
|
||||
private static Either<string, DateTime> TryAsDateTime(this JsonNode node, string propertyName) =>
|
||||
node.TryAsDateTime()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a valid DateTime.");
|
||||
public static string GetStringProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetStringProperty(propertyName)
|
||||
.IfLeftThrow();
|
||||
|
||||
public static JsonObject Parse<T>(T obj) =>
|
||||
TryParse(obj)
|
||||
.IfLeft(() => throw new JsonException($"Could not parse {typeof(T).Name} as a JSON object."));
|
||||
|
||||
private static Either<string, Uri> TryAsAbsoluteUri(this JsonNode node, string propertyName) =>
|
||||
node.TryAsAbsoluteUri()
|
||||
.ToEither(() => $"Property '{propertyName}' is not an absolute URI.");
|
||||
|
||||
public static int GetIntProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetIntProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, int> TryGetIntProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsInt(propertyName));
|
||||
|
||||
private static Either<string, int> TryAsInt(this JsonNode node, string propertyName) =>
|
||||
node.TryAsInt()
|
||||
.ToEither(() => $"Property '{propertyName}' is not an integer.");
|
||||
|
||||
public static double GetDoubleProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetDoubleProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, double> TryGetDoubleProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsDouble(propertyName));
|
||||
|
||||
private static Either<string, double> TryAsDouble(this JsonNode node, string propertyName) =>
|
||||
node.TryAsDouble()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a double.");
|
||||
|
||||
public static bool GetBoolProperty(this JsonObject jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetBoolProperty(propertyName)
|
||||
.IfLeftThrowJsonException();
|
||||
|
||||
public static Either<string, bool> TryGetBoolProperty(this JsonObject? jsonObject, string propertyName) =>
|
||||
jsonObject.TryGetProperty(propertyName)
|
||||
.Bind(node => node.TryAsBool(propertyName));
|
||||
|
||||
private static Either<string, bool> TryAsBool(this JsonNode node, string propertyName) =>
|
||||
node.TryAsBool()
|
||||
.ToEither(() => $"Property '{propertyName}' is not a boolean.");
|
||||
|
||||
private static T IfLeftThrowJsonException<T>(this Either<string, T> either)
|
||||
{
|
||||
return either.IfLeft(left => throw new JsonException(left));
|
||||
}
|
||||
public static Either<string, JsonObject> TryParse<T>(T obj) =>
|
||||
JsonSerializer.SerializeToNode(obj, SerializerOptions)
|
||||
.TryAsJsonObject();
|
||||
|
||||
[return: NotNullIfNotNull(nameof(jsonObject))]
|
||||
public static JsonObject? SetProperty(this JsonObject? jsonObject, string propertyName, JsonNode? jsonNode)
|
||||
|
@ -285,97 +156,4 @@ public static class JsonObjectExtensions
|
|||
return jsonObject;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets <paramref name="jsonObject"/>[<paramref name="propertyName"/>] = <paramref name="jsonNode"/> if <paramref name="jsonNode"/> is not null.
|
||||
/// </summary>
|
||||
[return: NotNullIfNotNull(nameof(jsonObject))]
|
||||
public static JsonObject? SetPropertyIfNotNull(this JsonObject? jsonObject, string propertyName, JsonNode? jsonNode) =>
|
||||
jsonNode is null
|
||||
? jsonObject
|
||||
: jsonObject.SetProperty(propertyName, jsonNode);
|
||||
|
||||
/// <summary>
|
||||
/// Sets <paramref name="jsonObject"/>'s property <paramref name="propertyName"/> to the value of <paramref name="option"/> if <paramref name="option"/> is Some.
|
||||
/// </summary>
|
||||
[return: NotNullIfNotNull(nameof(jsonObject))]
|
||||
public static JsonObject? SetPropertyIfSome(this JsonObject? jsonObject, string propertyName, Option<JsonNode> option) =>
|
||||
jsonObject.SetPropertyIfNotNull(propertyName, option.ValueUnsafe());
|
||||
|
||||
[return: NotNullIfNotNull(nameof(jsonObject))]
|
||||
public static JsonObject? RemoveProperty(this JsonObject? jsonObject, string propertyName)
|
||||
{
|
||||
if (jsonObject is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonObject.Remove(propertyName);
|
||||
return jsonObject;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly JsonSerializerOptions serializerOptions = new() { PropertyNameCaseInsensitive = true };
|
||||
|
||||
public static JsonObject Parse<T>(T obj) =>
|
||||
TryParse(obj)
|
||||
.IfNone(() => throw new JsonException($"Could not parse {typeof(T).Name} as a JSON object."));
|
||||
|
||||
public static Option<JsonObject> TryParse<T>(T obj) =>
|
||||
JsonSerializer.SerializeToNode(obj, serializerOptions)
|
||||
.TryAsJsonObject();
|
||||
}
|
||||
|
||||
public static class JsonValueExtensions
|
||||
{
|
||||
public static Option<string> TryAsString(this JsonValue? jsonValue) =>
|
||||
jsonValue is not null && jsonValue.TryGetValue<string>(out var value)
|
||||
? value
|
||||
: Option<string>.None;
|
||||
|
||||
public static Option<Guid> TryAsGuid(this JsonValue? jsonValue) =>
|
||||
jsonValue is not null && jsonValue.TryGetValue<Guid>(out var guid)
|
||||
? guid
|
||||
: jsonValue.TryAsString()
|
||||
.Bind(x => Guid.TryParse(x, out var guidFromString)
|
||||
? guidFromString
|
||||
: Option<Guid>.None);
|
||||
|
||||
public static Option<Uri> TryAsAbsoluteUri(this JsonValue? jsonValue) =>
|
||||
jsonValue.TryAsString()
|
||||
.Bind(x => Uri.TryCreate(x, UriKind.Absolute, out var uri)
|
||||
? uri
|
||||
: Option<Uri>.None);
|
||||
|
||||
public static Option<DateTimeOffset> TryAsDateTimeOffset(this JsonValue? jsonValue) =>
|
||||
jsonValue is not null && jsonValue.TryGetValue<DateTimeOffset>(out var dateTimeOffset)
|
||||
? dateTimeOffset
|
||||
: jsonValue.TryAsString()
|
||||
.Bind(x => DateTimeOffset.TryParse(x, out var dateTime)
|
||||
? dateTime
|
||||
: Option<DateTimeOffset>.None);
|
||||
|
||||
public static Option<DateTime> TryAsDateTime(this JsonValue? jsonValue) =>
|
||||
jsonValue is not null && jsonValue.TryGetValue<DateTime>(out var dateTime)
|
||||
? dateTime
|
||||
: jsonValue.TryAsString()
|
||||
.Bind(x => DateTime.TryParse(x, out var dateTime)
|
||||
? dateTime
|
||||
: Option<DateTime>.None);
|
||||
|
||||
public static Option<int> TryAsInt(this JsonValue? jsonValue) =>
|
||||
jsonValue is not null && jsonValue.TryGetValue<int>(out var value)
|
||||
? value
|
||||
: Option<int>.None;
|
||||
|
||||
public static Option<double> TryAsDouble(this JsonValue? jsonValue) =>
|
||||
jsonValue is not null && jsonValue.TryGetValue<double>(out var value)
|
||||
? value
|
||||
: Option<double>.None;
|
||||
|
||||
public static Option<bool> TryAsBool(this JsonValue? jsonValue) =>
|
||||
jsonValue is not null && jsonValue.TryGetValue<bool>(out var value)
|
||||
? value
|
||||
: Option<bool>.None;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
|
@ -17,12 +16,6 @@ public sealed record LoggerName : ResourceName
|
|||
{
|
||||
private LoggerName(string value) : base(value) { }
|
||||
|
||||
/// <summary>
|
||||
/// Logger names with revisions have the format 'loggerName;revision'
|
||||
/// </summary>
|
||||
public LoggerName ToNonRevisionedName() =>
|
||||
new(Value.Split(';').First());
|
||||
|
||||
public static LoggerName From(string value) => new(value);
|
||||
}
|
||||
|
||||
|
@ -181,17 +174,6 @@ public static class LoggerModule
|
|||
return content.ToObjectFromJson<LoggerDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<LoggerDto>> TryGetDto(this LoggerUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<LoggerDto>())
|
||||
.Match(Option<LoggerDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<LoggerDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this LoggerUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -19,6 +19,15 @@ public sealed record ManagementServiceDirectory : ResourceDirectory
|
|||
public static ManagementServiceDirectory From(DirectoryInfo value) => new(value);
|
||||
}
|
||||
|
||||
public sealed record ManagementServiceProviderUri : ResourceUri
|
||||
{
|
||||
private ManagementServiceProviderUri(Uri value) => Value = value;
|
||||
|
||||
protected override Uri Value { get; }
|
||||
|
||||
public static ManagementServiceProviderUri From(Uri value) => new(value);
|
||||
}
|
||||
|
||||
public sealed record ManagementServiceUri : ResourceUri
|
||||
{
|
||||
private ManagementServiceUri(Uri value) => Value = value;
|
||||
|
|
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -186,17 +185,6 @@ public static class NamedValueModule
|
|||
return content.ToObjectFromJson<NamedValueDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<NamedValueDto>> TryGetDto(this NamedValueUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<NamedValueDto>())
|
||||
.Match(Option<NamedValueDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<NamedValueDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this NamedValueUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Azure.Monitor.OpenTelemetry.AspNetCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OpenTelemetry.Instrumentation.Http;
|
||||
using OpenTelemetry.Logs;
|
||||
using OpenTelemetry.Metrics;
|
||||
using OpenTelemetry.Trace;
|
||||
|
@ -9,22 +11,34 @@ using System.Diagnostics;
|
|||
|
||||
namespace common;
|
||||
|
||||
public static class OpenTelemetryServices
|
||||
public static class OpenTelemetryModule
|
||||
{
|
||||
public static void Configure(IServiceCollection services)
|
||||
public static void Configure(IHostApplicationBuilder builder, string activitySourceName)
|
||||
{
|
||||
var sourceName = services.BuildServiceProvider().GetService<ActivitySource>()?.Name ?? "ApiOps.*";
|
||||
builder.Logging.AddOpenTelemetry(Configure);
|
||||
Configure(builder.Services, builder.Configuration, activitySourceName);
|
||||
}
|
||||
|
||||
private static void Configure(OpenTelemetryLoggerOptions options)
|
||||
{
|
||||
options.IncludeFormattedMessage = true;
|
||||
options.IncludeScopes = true;
|
||||
}
|
||||
|
||||
private static void Configure(IServiceCollection services, IConfiguration configuration, string activitySourceName)
|
||||
{
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
||||
services.TryAddSingleton(new ActivitySource(activitySourceName));
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
services.AddOpenTelemetry()
|
||||
.WithMetrics(metrics => metrics.AddHttpClientInstrumentation()
|
||||
.AddRuntimeInstrumentation()
|
||||
.AddMeter("Azure.*"))
|
||||
.WithTracing(tracing => tracing.AddHttpClientInstrumentation(ConfigureHttpClientTraceInstrumentationOptions)
|
||||
.AddSource("Azure.*")
|
||||
.AddSource(sourceName)
|
||||
.AddMeter("*"))
|
||||
.WithTracing(tracing => tracing.AddHttpClientInstrumentation()
|
||||
.AddSource("*")
|
||||
.SetSampler<AlwaysOnSampler>());
|
||||
|
||||
var configuration = services.BuildServiceProvider().GetRequiredService<IConfiguration>();
|
||||
configuration.TryGetValue("OTEL_EXPORTER_OTLP_ENDPOINT")
|
||||
.Iter(_ =>
|
||||
{
|
||||
|
@ -33,10 +47,9 @@ public static class OpenTelemetryServices
|
|||
.ConfigureOpenTelemetryMeterProvider(metrics => metrics.AddOtlpExporter())
|
||||
.ConfigureOpenTelemetryTracerProvider(tracing => tracing.AddOtlpExporter());
|
||||
});
|
||||
}
|
||||
|
||||
private static void ConfigureHttpClientTraceInstrumentationOptions(HttpClientTraceInstrumentationOptions options)
|
||||
{
|
||||
options.FilterHttpRequestMessage = (_) => Activity.Current?.Parent?.Source?.Name != "Azure.Core.Http";
|
||||
configuration.TryGetValue("APPLICATIONINSIGHTS_CONNECTION_STRING")
|
||||
.Iter(_ => services.AddOpenTelemetry()
|
||||
.UseAzureMonitor());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,28 +46,6 @@ public static class OptionExtensions
|
|||
public static async ValueTask<Option<T2>> BindTask<T, T2>(this Option<T> option, Func<T, CancellationToken, ValueTask<Option<T2>>> bind, CancellationToken cancellationToken) =>
|
||||
await option.Match(t => bind(t, cancellationToken), () => ValueTask.FromResult(Option<T2>.None));
|
||||
|
||||
public static async ValueTask<Option<T>> Where<T>(this Option<T> option, Func<T, ValueTask<bool>> predicate) =>
|
||||
await option.BindTask(async t => await predicate(t)
|
||||
? Option<T>.Some(t)
|
||||
: Option<T>.None);
|
||||
|
||||
/// <summary>
|
||||
/// Run each function until one returns Some. If none return Some, return None.
|
||||
/// </summary>
|
||||
public static async ValueTask<Option<T>> PickFirst<T>(this IEnumerable<Func<ValueTask<Option<T>>>> functions, CancellationToken cancellationToken) =>
|
||||
await functions.ToAsyncEnumerable()
|
||||
.Pick(async f => await f(), cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Run each function until one returns Some. If none return Some, return None.
|
||||
/// </summary>
|
||||
public static async ValueTask<Option<T>> PickFirst<T>(this IEnumerable<Func<Task<Option<T>>>> functions, CancellationToken cancellationToken) =>
|
||||
await functions.ToAsyncEnumerable()
|
||||
.Pick(async f => await f(), cancellationToken);
|
||||
|
||||
public static Option<T> Or<T>(this Option<T> option, Func<Option<T>> alternative) =>
|
||||
option.Match(Option<T>.Some, alternative);
|
||||
|
||||
public static async ValueTask<Option<T>> Or<T>(this Option<T> option, Func<ValueTask<Option<T>>> alternative) =>
|
||||
await option.Match(t => ValueTask.FromResult(Option<T>.Some(t)), alternative);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -192,17 +191,6 @@ public static class PolicyFragmentModule
|
|||
return content.ToObjectFromJson<PolicyFragmentDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<PolicyFragmentDto>> TryGetDto(this PolicyFragmentUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<PolicyFragmentDto>())
|
||||
.Match(Option<PolicyFragmentDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<PolicyFragmentDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this PolicyFragmentUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -182,17 +181,6 @@ public static class ProductModule
|
|||
return content.ToObjectFromJson<ProductDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<ProductDto>> TryGetDto(this ProductUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<ProductDto>())
|
||||
.Match(Option<ProductDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<ProductDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this ProductUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -124,17 +124,6 @@ public static class ProductPolicyModule
|
|||
return content.ToObjectFromJson<ProductPolicyDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<ProductPolicyDto>> TryGetDto(this ProductPolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<ProductPolicyDto>())
|
||||
.Match(Option<ProductPolicyDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<ProductPolicyDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this ProductPolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -124,17 +124,6 @@ public static class ServicePolicyModule
|
|||
return content.ToObjectFromJson<ServicePolicyDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<ServicePolicyDto>> TryGetDto(this ServicePolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<ServicePolicyDto>())
|
||||
.Match(Option<ServicePolicyDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<ServicePolicyDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this ServicePolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -73,7 +72,7 @@ public sealed record SubscriptionDirectory : ResourceDirectory
|
|||
public required SubscriptionName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.Value);
|
||||
|
||||
public static SubscriptionDirectory From(SubscriptionName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
|
@ -94,7 +93,8 @@ public sealed record SubscriptionDirectory : ResourceDirectory
|
|||
public sealed record SubscriptionInformationFile : ResourceFile
|
||||
{
|
||||
public required SubscriptionDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "subscriptionInformation.json";
|
||||
|
||||
public static string Name { get; } = "subscriptionInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
@ -102,17 +102,14 @@ public sealed record SubscriptionInformationFile : ResourceFile
|
|||
public static SubscriptionInformationFile From(SubscriptionName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = new SubscriptionDirectory
|
||||
{
|
||||
Parent = SubscriptionsDirectory.From(serviceDirectory),
|
||||
Name = name
|
||||
}
|
||||
Parent = SubscriptionDirectory.From(name, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<SubscriptionInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null && file.Name == Name
|
||||
file is not null &&
|
||||
file.Name == Name
|
||||
? from parent in SubscriptionDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new SubscriptionInformationFile { Parent = parent }
|
||||
select From(parent.Name, serviceDirectory)
|
||||
: Option<SubscriptionInformationFile>.None;
|
||||
}
|
||||
|
||||
|
@ -158,23 +155,25 @@ public static class SubscriptionModule
|
|||
{
|
||||
public static async ValueTask DeleteAll(this SubscriptionsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await uri.ListNames(pipeline, cancellationToken)
|
||||
.IterParallel(async name => await SubscriptionUri.From(name, uri.ServiceUri)
|
||||
.Delete(pipeline, cancellationToken),
|
||||
cancellationToken);
|
||||
.IterParallel(async name =>
|
||||
{
|
||||
var resourceUri = SubscriptionUri.From(name, uri.ServiceUri);
|
||||
await resourceUri.Delete(pipeline, cancellationToken);
|
||||
}, cancellationToken);
|
||||
|
||||
public static IAsyncEnumerable<SubscriptionName> ListNames(this SubscriptionsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(SubscriptionName.From);
|
||||
|
||||
public static IAsyncEnumerable<(SubscriptionName Name, SubscriptionDto Dto)> List(this SubscriptionsUri subscriptionsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
subscriptionsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new SubscriptionUri { Parent = subscriptionsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
public static IAsyncEnumerable<(SubscriptionName Name, SubscriptionDto Dto)> List(this SubscriptionsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
uri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var resourceUri = new SubscriptionUri { Parent = uri, Name = name };
|
||||
var dto = await resourceUri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<SubscriptionDto> GetDto(this SubscriptionUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -182,17 +181,6 @@ public static class SubscriptionModule
|
|||
return content.ToObjectFromJson<SubscriptionDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<SubscriptionDto>> TryGetDto(this SubscriptionUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<SubscriptionDto>())
|
||||
.Match(Option<SubscriptionDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<SubscriptionDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this SubscriptionUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -59,8 +58,7 @@ public sealed record TagsDirectory : ResourceDirectory
|
|||
new() { ServiceDirectory = serviceDirectory };
|
||||
|
||||
public static Option<TagsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
directory is not null &&
|
||||
directory.Name == Name &&
|
||||
directory?.Name == Name &&
|
||||
directory.Parent?.FullName == serviceDirectory.ToDirectoryInfo().FullName
|
||||
? new TagsDirectory { ServiceDirectory = serviceDirectory }
|
||||
: Option<TagsDirectory>.None;
|
||||
|
@ -102,15 +100,11 @@ public sealed record TagInformationFile : ResourceFile
|
|||
public static TagInformationFile From(TagName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = new TagDirectory
|
||||
{
|
||||
Parent = TagsDirectory.From(serviceDirectory),
|
||||
Name = name
|
||||
}
|
||||
Parent = TagDirectory.From(name, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<TagInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null && file.Name == Name
|
||||
file?.Name == Name
|
||||
? from parent in TagDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new TagInformationFile { Parent = parent }
|
||||
: Option<TagInformationFile>.None;
|
||||
|
@ -145,12 +139,12 @@ public static class TagModule
|
|||
|
||||
public static IAsyncEnumerable<(TagName Name, TagDto Dto)> List(this TagsUri tagsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
tagsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new TagUri { Parent = tagsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new TagUri { Parent = tagsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<TagDto> GetDto(this TagUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -158,17 +152,6 @@ public static class TagModule
|
|||
return content.ToObjectFromJson<TagDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<TagDto>> TryGetDto(this TagUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<TagDto>())
|
||||
.Match(Option<TagDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<TagDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this TagUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
@ -183,9 +166,9 @@ public static class TagModule
|
|||
var tagsDirectory = TagsDirectory.From(serviceDirectory);
|
||||
|
||||
return tagsDirectory.ToDirectoryInfo()
|
||||
.ListDirectories("*")
|
||||
.Select(directoryInfo => TagName.From(directoryInfo.Name))
|
||||
.Select(name => new TagDirectory { Parent = tagsDirectory, Name = name });
|
||||
.ListDirectories("*")
|
||||
.Select(directoryInfo => TagName.From(directoryInfo.Name))
|
||||
.Select(name => new TagDirectory { Parent = tagsDirectory, Name = name });
|
||||
}
|
||||
|
||||
public static IEnumerable<TagInformationFile> ListInformationFiles(ManagementServiceDirectory serviceDirectory) =>
|
||||
|
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -174,17 +173,6 @@ public static class VersionSetModule
|
|||
return content.ToObjectFromJson<VersionSetDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<VersionSetDto>> TryGetDto(this VersionSetUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var either = await pipeline.TryGetContent(uri.ToUri(), cancellationToken);
|
||||
|
||||
return either.Map(content => content.ToObjectFromJson<VersionSetDto>())
|
||||
.Match(Option<VersionSetDto>.Some,
|
||||
response => response.Status == (int)HttpStatusCode.NotFound
|
||||
? Option<VersionSetDto>.None
|
||||
: throw response.ToHttpRequestException(uri.ToUri()));
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this VersionSetUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceName : ResourceName
|
||||
{
|
||||
private WorkspaceName(string value) : base(value) { }
|
||||
|
||||
public static WorkspaceName From(string value) => new(value);
|
||||
}
|
||||
|
||||
public sealed record WorkspacesUri : ResourceUri
|
||||
{
|
||||
public required ManagementServiceUri ServiceUri { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "workspaces";
|
||||
|
||||
protected override Uri Value =>
|
||||
ServiceUri.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspacesUri From(ManagementServiceUri serviceUri) =>
|
||||
new() { ServiceUri = serviceUri };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceUri : ResourceUri
|
||||
{
|
||||
public required WorkspacesUri Parent { get; init; }
|
||||
|
||||
public required WorkspaceName Name { get; init; }
|
||||
|
||||
protected override Uri Value =>
|
||||
Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspacesUri.From(serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspacesDirectory : ResourceDirectory
|
||||
{
|
||||
public required ManagementServiceDirectory ServiceDirectory { get; init; }
|
||||
|
||||
private static string Name { get; } = "workspaces";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
ServiceDirectory.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspacesDirectory From(ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { ServiceDirectory = serviceDirectory };
|
||||
|
||||
public static Option<WorkspacesDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
directory is not null &&
|
||||
directory.Name == Name &&
|
||||
directory.Parent?.FullName == serviceDirectory.ToDirectoryInfo().FullName
|
||||
? new WorkspacesDirectory { ServiceDirectory = serviceDirectory }
|
||||
: Option<WorkspacesDirectory>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspacesDirectory Parent { get; init; }
|
||||
|
||||
public required WorkspaceName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.Value);
|
||||
|
||||
public static WorkspaceDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspacesDirectory.From(serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
directory is not null
|
||||
? from parent in WorkspacesDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
let name = WorkspaceName.From(directory!.Name)
|
||||
select new WorkspaceDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = name
|
||||
}
|
||||
: Option<WorkspaceDirectory>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
|
||||
public static string Name { get; } = "workspaceInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceInformationFile From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceDirectory.From(name, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null &&
|
||||
file.Name == Name
|
||||
? from parent in WorkspaceDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceInformationFile
|
||||
{
|
||||
Parent = parent
|
||||
}
|
||||
: Option<WorkspaceInformationFile>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required WorkspaceContract Properties { get; init; }
|
||||
|
||||
public sealed record WorkspaceContract
|
||||
{
|
||||
[JsonPropertyName("displayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? DisplayName { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceModule
|
||||
{
|
||||
public static async ValueTask DeleteAll(this WorkspacesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await uri.ListNames(pipeline, cancellationToken)
|
||||
.IterParallel(async name =>
|
||||
{
|
||||
var resourceUri = new WorkspaceUri { Parent = uri, Name = name };
|
||||
await resourceUri.Delete(pipeline, cancellationToken);
|
||||
}, cancellationToken);
|
||||
|
||||
public static IAsyncEnumerable<WorkspaceName> ListNames(this WorkspacesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var exceptionHandler = (HttpRequestException exception) =>
|
||||
exception.StatusCode == HttpStatusCode.BadRequest
|
||||
&& exception.Message.Contains("MethodNotAllowedInPricingTier", StringComparison.OrdinalIgnoreCase)
|
||||
? AsyncEnumerable.Empty<WorkspaceName>()
|
||||
: throw exception;
|
||||
|
||||
return pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(WorkspaceName.From)
|
||||
.Catch(exceptionHandler);
|
||||
}
|
||||
|
||||
public static IAsyncEnumerable<(WorkspaceName Name, WorkspaceDto Dto)> List(this WorkspacesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
uri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var resourceUri = new WorkspaceUri { Parent = uri, Name = name };
|
||||
var dto = await resourceUri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceDto> GetDto(this WorkspaceUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceUri uri, WorkspaceDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static IEnumerable<WorkspaceDirectory> ListDirectories(ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
var workspacesDirectory = WorkspacesDirectory.From(serviceDirectory);
|
||||
|
||||
return from workspacesDirectoryInfo in workspacesDirectory.ToDirectoryInfo().ListDirectories("*")
|
||||
let name = WorkspaceName.From(workspacesDirectoryInfo.Name)
|
||||
select new WorkspaceDirectory
|
||||
{
|
||||
Parent = workspacesDirectory,
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<WorkspaceInformationFile> ListInformationFiles(ManagementServiceDirectory serviceDirectory) =>
|
||||
from workspaceDirectory in ListDirectories(serviceDirectory)
|
||||
let informationFile = new WorkspaceInformationFile { Parent = workspaceDirectory }
|
||||
where informationFile.ToFileInfo().Exists()
|
||||
select informationFile;
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceInformationFile file, WorkspaceDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceDto> ReadDto(this WorkspaceInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,672 @@
|
|||
using Azure;
|
||||
using Azure.Core;
|
||||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using Polly;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using YamlDotNet.System.Text.Json;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceApisUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "apis";
|
||||
|
||||
protected override Uri Value =>
|
||||
Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceApisUri From(WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(workspaceName, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceApisUri Parent { get; init; }
|
||||
|
||||
public required ApiName Name { get; init; }
|
||||
|
||||
protected override Uri Value =>
|
||||
Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceApiUri From(ApiName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceApisUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApisDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "apis";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceApisDirectory From(WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(workspaceName, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceApisDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
directory is not null
|
||||
&& directory.Name == Name
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceApisDirectory { Parent = parent }
|
||||
: Option<WorkspaceApisDirectory>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceApisDirectory Parent { get; init; }
|
||||
|
||||
public required ApiName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.Value);
|
||||
|
||||
public static WorkspaceApiDirectory From(ApiName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceApisDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceApiDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
directory is not null
|
||||
? from parent in WorkspaceApisDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
let name = ApiName.From(directory!.Name)
|
||||
select new WorkspaceApiDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = name
|
||||
}
|
||||
: Option<WorkspaceApiDirectory>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceApiDirectory Parent { get; init; }
|
||||
|
||||
public static string Name { get; } = "apiInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceApiInformationFile From(ApiName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceApiDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceApiInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null &&
|
||||
file.Name == Name
|
||||
? from parent in WorkspaceApiDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceApiInformationFile
|
||||
{
|
||||
Parent = parent
|
||||
}
|
||||
: Option<WorkspaceApiInformationFile>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required ApiCreateOrUpdateProperties Properties { get; init; }
|
||||
|
||||
public record ApiCreateOrUpdateProperties
|
||||
{
|
||||
[JsonPropertyName("path")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Path { get; init; }
|
||||
|
||||
[JsonPropertyName("apiRevision")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ApiRevision { get; init; }
|
||||
|
||||
[JsonPropertyName("apiRevisionDescription")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ApiRevisionDescription { get; init; }
|
||||
|
||||
[JsonPropertyName("apiVersion")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ApiVersion { get; init; }
|
||||
|
||||
[JsonPropertyName("apiVersionDescription")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ApiVersionDescription { get; init; }
|
||||
|
||||
[JsonPropertyName("apiVersionSetId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ApiVersionSetId { get; init; }
|
||||
|
||||
[JsonPropertyName("authenticationSettings")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public AuthenticationSettingsContract? AuthenticationSettings { get; init; }
|
||||
|
||||
[JsonPropertyName("contact")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ApiContactInformation? Contact { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("isCurrent")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? IsCurrent { get; init; }
|
||||
|
||||
[JsonPropertyName("license")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ApiLicenseInformation? License { get; init; }
|
||||
|
||||
[JsonPropertyName("apiType")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ApiType { get; init; }
|
||||
|
||||
[JsonPropertyName("apiVersionSet")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ApiVersionSetContractDetails? ApiVersionSet { get; init; }
|
||||
|
||||
[JsonPropertyName("displayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? DisplayName { get; init; }
|
||||
|
||||
[JsonPropertyName("format")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Format { get; init; }
|
||||
|
||||
[JsonPropertyName("protocols")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableArray<string>? Protocols { get; init; }
|
||||
|
||||
[JsonPropertyName("serviceUrl")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
#pragma warning disable CA1056 // URI-like properties should not be strings
|
||||
public string? ServiceUrl { get; init; }
|
||||
#pragma warning restore CA1056 // URI-like properties should not be strings
|
||||
|
||||
[JsonPropertyName("sourceApiId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? SourceApiId { get; init; }
|
||||
|
||||
[JsonPropertyName("translateRequiredQueryParameters")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? TranslateRequiredQueryParameters { get; init; }
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Value { get; init; }
|
||||
|
||||
[JsonPropertyName("wsdlSelector")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public WsdlSelectorContract? WsdlSelector { get; init; }
|
||||
|
||||
[JsonPropertyName("subscriptionKeyParameterNames")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public SubscriptionKeyParameterNamesContract? SubscriptionKeyParameterNames { get; init; }
|
||||
|
||||
[JsonPropertyName("subscriptionRequired")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? SubscriptionRequired { get; init; }
|
||||
|
||||
[JsonPropertyName("termsOfServiceUrl")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
#pragma warning disable CA1056 // URI-like properties should not be strings
|
||||
public string? TermsOfServiceUrl { get; init; }
|
||||
#pragma warning restore CA1056 // URI-like properties should not be strings
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Type { get; init; }
|
||||
|
||||
public record AuthenticationSettingsContract
|
||||
{
|
||||
[JsonPropertyName("oAuth2")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public OAuth2AuthenticationSettingsContract? OAuth2 { get; init; }
|
||||
|
||||
[JsonPropertyName("openid")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public OpenIdAuthenticationSettingsContract? OpenId { get; init; }
|
||||
}
|
||||
|
||||
public record OAuth2AuthenticationSettingsContract
|
||||
{
|
||||
[JsonPropertyName("authorizationServerId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? AuthorizationServerId { get; init; }
|
||||
|
||||
[JsonPropertyName("scope")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Scope { get; init; }
|
||||
}
|
||||
|
||||
public record OpenIdAuthenticationSettingsContract
|
||||
{
|
||||
[JsonPropertyName("bearerTokenSendingMethods")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableArray<string>? BearerTokenSendingMethods { get; init; }
|
||||
|
||||
[JsonPropertyName("openidProviderId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? OpenIdProviderId { get; init; }
|
||||
}
|
||||
|
||||
public record ApiContactInformation
|
||||
{
|
||||
[JsonPropertyName("email")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Email { get; init; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Name { get; init; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
#pragma warning disable CA1056 // URI-like properties should not be strings
|
||||
public string? Url { get; init; }
|
||||
#pragma warning restore CA1056 // URI-like properties should not be strings
|
||||
}
|
||||
|
||||
public record ApiLicenseInformation
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Name { get; init; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
#pragma warning disable CA1056 // URI-like properties should not be strings
|
||||
public string? Url { get; init; }
|
||||
#pragma warning restore CA1056 // URI-like properties should not be strings
|
||||
}
|
||||
|
||||
public record ApiVersionSetContractDetails
|
||||
{
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Id { get; init; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Name { get; init; }
|
||||
|
||||
[JsonPropertyName("versionHeaderName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? VersionHeaderName { get; init; }
|
||||
|
||||
[JsonPropertyName("versionQueryName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? VersionQueryName { get; init; }
|
||||
|
||||
[JsonPropertyName("versioningScheme")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? VersioningScheme { get; init; }
|
||||
}
|
||||
|
||||
public record SubscriptionKeyParameterNamesContract
|
||||
{
|
||||
[JsonPropertyName("header")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Header { get; init; }
|
||||
|
||||
[JsonPropertyName("query")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Query { get; init; }
|
||||
}
|
||||
|
||||
public record WsdlSelectorContract
|
||||
{
|
||||
[JsonPropertyName("wsdlEndpointName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? WsdlEndpointName { get; init; }
|
||||
|
||||
[JsonPropertyName("wsdlServiceName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? WsdlServiceName { get; init; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceApiModule
|
||||
{
|
||||
public static async ValueTask DeleteAll(this WorkspaceApisUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await uri.ListNames(pipeline, cancellationToken)
|
||||
.IterParallel(async name =>
|
||||
{
|
||||
var resourceUri = new WorkspaceApiUri { Parent = uri, Name = name };
|
||||
await resourceUri.Delete(pipeline, cancellationToken);
|
||||
}, cancellationToken);
|
||||
|
||||
public static IAsyncEnumerable<ApiName> ListNames(this WorkspaceApisUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(ApiName.From);
|
||||
|
||||
public static IAsyncEnumerable<(ApiName Name, WorkspaceApiDto Dto)> List(this WorkspaceApisUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
uri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var resourceUri = new WorkspaceApiUri { Parent = uri, Name = name };
|
||||
var dto = await resourceUri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceApiDto> GetDto(this WorkspaceApiUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceApiDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<BinaryData>> TryGetSpecificationContents(this WorkspaceApiUri apiUri, ApiSpecification specification, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
if (specification is ApiSpecification.GraphQl)
|
||||
{
|
||||
return await apiUri.TryGetGraphQlSchema(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
BinaryData? content;
|
||||
try
|
||||
{
|
||||
var exportUri = GetExportUri(apiUri, specification, includeLink: true);
|
||||
var downloadUri = await GetSpecificationDownloadUri(exportUri, pipeline, cancellationToken);
|
||||
|
||||
var nonAuthenticatedHttpPipeline = HttpPipelineBuilder.Build(ClientOptions.Default);
|
||||
content = await nonAuthenticatedHttpPipeline.GetContent(downloadUri, cancellationToken);
|
||||
}
|
||||
// If we can't download the specification through the download link, get it directly.
|
||||
catch (HttpRequestException exception) when (exception.StatusCode == HttpStatusCode.InternalServerError)
|
||||
{
|
||||
// Don't export XML specifications, as the non-link exports cannot be reimported.
|
||||
if (specification is ApiSpecification.Wsdl or ApiSpecification.Wadl)
|
||||
{
|
||||
return Option<BinaryData>.None;
|
||||
}
|
||||
|
||||
var exportUri = GetExportUri(apiUri, specification, includeLink: false);
|
||||
var json = await pipeline.GetJsonObject(exportUri, cancellationToken);
|
||||
var contentString = json.GetProperty("value") switch
|
||||
{
|
||||
JsonValue jsonValue => jsonValue.ToString(),
|
||||
var node => node.ToJsonString(JsonObjectExtensions.SerializerOptions)
|
||||
};
|
||||
content = BinaryData.FromString(contentString);
|
||||
}
|
||||
|
||||
// APIM exports OpenApiV2 to JSON. Convert to YAML if needed.
|
||||
if (specification is ApiSpecification.OpenApi openApi && openApi.Format is OpenApiFormat.Yaml && openApi.Version is OpenApiVersion.V2)
|
||||
{
|
||||
var yaml = YamlConverter.SerializeJson(content.ToString());
|
||||
content = BinaryData.FromString(yaml);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
private static Uri GetExportUri(WorkspaceApiUri apiUri, ApiSpecification specification, bool includeLink)
|
||||
{
|
||||
var format = GetExportFormat(specification, includeLink);
|
||||
|
||||
return apiUri.ToUri()
|
||||
.SetQueryParam("format", format)
|
||||
.SetQueryParam("export", "true")
|
||||
.SetQueryParam("api-version", "2022-09-01-preview")
|
||||
.ToUri();
|
||||
}
|
||||
|
||||
private static string GetExportFormat(ApiSpecification specification, bool includeLink)
|
||||
{
|
||||
var formatWithoutLink = specification switch
|
||||
{
|
||||
ApiSpecification.Wadl => "wadl",
|
||||
ApiSpecification.Wsdl => "wsdl",
|
||||
ApiSpecification.OpenApi openApiSpecification =>
|
||||
(openApiSpecification.Version, openApiSpecification.Format) switch
|
||||
{
|
||||
(OpenApiVersion.V2, _) => "swagger",
|
||||
(OpenApiVersion.V3, OpenApiFormat.Yaml) => "openapi",
|
||||
(OpenApiVersion.V3, OpenApiFormat.Json) => "openapi+json",
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
return includeLink ? $"{formatWithoutLink}-link" : formatWithoutLink;
|
||||
}
|
||||
|
||||
private static async ValueTask<Uri> GetSpecificationDownloadUri(Uri exportUri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var json = await pipeline.GetJsonObject(exportUri, cancellationToken);
|
||||
|
||||
return json.GetJsonObjectProperty("properties")
|
||||
.GetJsonObjectProperty("value")
|
||||
.GetAbsoluteUriProperty("link");
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceApiUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask DeleteAllRevisions(this WorkspaceApiUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri()
|
||||
.SetQueryParam("deleteRevisions", "true")
|
||||
.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceApiUri uri, WorkspaceApiDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
if (dto.Properties.Format is null && dto.Properties.Value is null)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dto.Properties.Type is "soap")
|
||||
{
|
||||
await PutSoapApi(uri, dto, pipeline, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await PutNonSoapApi(uri, dto, pipeline, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
using var _ =
|
||||
await new ResiliencePipelineBuilder<Response>()
|
||||
.AddRetry(new()
|
||||
{
|
||||
BackoffType = DelayBackoffType.Exponential,
|
||||
UseJitter = true,
|
||||
MaxRetryAttempts = 5,
|
||||
ShouldHandle = new PredicateBuilder<Response>().HandleResult(CreationInProgress)
|
||||
})
|
||||
.Build()
|
||||
.ExecuteAsync(async cancellationToken =>
|
||||
{
|
||||
using var request = pipeline.CreateRequest(uri.ToUri(), RequestMethod.Get);
|
||||
return await pipeline.SendRequestAsync(request, cancellationToken);
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
private static async ValueTask PutSoapApi(WorkspaceApiUri uri, WorkspaceApiDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
// Import API with specification
|
||||
var soapUri = uri.ToUri().SetQueryParam("import", "true").ToUri();
|
||||
var soapDto = new ApiDto
|
||||
{
|
||||
Properties = new ApiDto.ApiCreateOrUpdateProperties
|
||||
{
|
||||
Format = "wsdl",
|
||||
Value = dto.Properties.Value,
|
||||
ApiType = "soap",
|
||||
DisplayName = dto.Properties.DisplayName,
|
||||
Path = dto.Properties.Path,
|
||||
Protocols = dto.Properties.Protocols,
|
||||
ApiVersion = dto.Properties.ApiVersion,
|
||||
ApiVersionDescription = dto.Properties.ApiVersionDescription,
|
||||
ApiVersionSetId = dto.Properties.ApiVersionSetId
|
||||
}
|
||||
};
|
||||
await pipeline.PutContent(soapUri, BinaryData.FromObjectAsJson(soapDto), cancellationToken);
|
||||
|
||||
// Put API again without specification
|
||||
var updatedDto = dto with { Properties = dto.Properties with { Format = null, Value = null } };
|
||||
// SOAP apis sometimes fail on put; retry if needed
|
||||
await soapApiResiliencePipeline.Value
|
||||
.ExecuteAsync(async cancellationToken => await pipeline.PutContent(uri.ToUri(), BinaryData.FromObjectAsJson(updatedDto), cancellationToken), cancellationToken);
|
||||
}
|
||||
|
||||
private static readonly Lazy<ResiliencePipeline> soapApiResiliencePipeline = new(() =>
|
||||
new ResiliencePipelineBuilder()
|
||||
.AddRetry(new()
|
||||
{
|
||||
BackoffType = DelayBackoffType.Exponential,
|
||||
UseJitter = true,
|
||||
MaxRetryAttempts = 3,
|
||||
ShouldHandle = new PredicateBuilder().Handle<HttpRequestException>(exception => exception.StatusCode == HttpStatusCode.Conflict && exception.Message.Contains("IdentifierAlreadyInUse", StringComparison.OrdinalIgnoreCase))
|
||||
})
|
||||
.Build());
|
||||
|
||||
private static async ValueTask PutNonSoapApi(WorkspaceApiUri uri, WorkspaceApiDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
// Put API without the specification.
|
||||
var modelWithoutSpecification = dto with
|
||||
{
|
||||
Properties = dto.Properties with
|
||||
{
|
||||
Format = null,
|
||||
Value = null,
|
||||
ServiceUrl = null,
|
||||
Type = dto.Properties.Type,
|
||||
ApiType = dto.Properties.ApiType
|
||||
}
|
||||
};
|
||||
await pipeline.PutContent(uri.ToUri(), BinaryData.FromObjectAsJson(modelWithoutSpecification), cancellationToken);
|
||||
|
||||
// Put API again with specification
|
||||
await pipeline.PutContent(uri.ToUri(), BinaryData.FromObjectAsJson(dto), cancellationToken);
|
||||
}
|
||||
|
||||
private static bool CreationInProgress(Response response)
|
||||
{
|
||||
if (response.Status != (int)HttpStatusCode.Created)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (response.Headers.Any(header => header.Name.Equals("Content-Type", StringComparison.OrdinalIgnoreCase)
|
||||
&& header.Value.Contains("application/json", StringComparison.OrdinalIgnoreCase)) is false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return response.Content.ToObjectFromJson<JsonObject>()
|
||||
.TryGetJsonObjectProperty("properties")
|
||||
.Bind(json => json.TryGetStringProperty("ProvisioningState"))
|
||||
.ToOption()
|
||||
.Where(state => state.Equals("InProgress", StringComparison.OrdinalIgnoreCase))
|
||||
.IsSome;
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async ValueTask PutGraphQlSchema(this WorkspaceApiUri uri, BinaryData schema, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var contents = BinaryData.FromObjectAsJson(new JsonObject()
|
||||
{
|
||||
["properties"] = new JsonObject
|
||||
{
|
||||
["contentType"] = "application/vnd.ms-azure-apim.graphql.schema",
|
||||
["document"] = new JsonObject()
|
||||
{
|
||||
["value"] = schema.ToString()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await pipeline.PutContent(uri.ToUri()
|
||||
.AppendPathSegment("schemas")
|
||||
.AppendPathSegment("graphql")
|
||||
.ToUri(), contents, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<Option<BinaryData>> TryGetGraphQlSchema(this WorkspaceApiUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var schemaUri = uri.ToUri()
|
||||
.AppendPathSegment("schemas")
|
||||
.AppendPathSegment("graphql")
|
||||
.ToUri();
|
||||
|
||||
var schemaJsonOption = await pipeline.GetJsonObjectOption(schemaUri, cancellationToken);
|
||||
|
||||
return schemaJsonOption.Map(GetGraphQlSpecificationFromSchemaResponse);
|
||||
}
|
||||
|
||||
private static BinaryData GetGraphQlSpecificationFromSchemaResponse(JsonObject responseJson)
|
||||
{
|
||||
var schema = responseJson.GetJsonObjectProperty("properties")
|
||||
.GetJsonObjectProperty("document")
|
||||
.GetNonEmptyOrWhiteSpaceStringProperty("value");
|
||||
|
||||
return BinaryData.FromString(schema);
|
||||
}
|
||||
|
||||
public static IEnumerable<WorkspaceApiDirectory> ListDirectories(ManagementServiceDirectory serviceDirectory) =>
|
||||
from workspaceDirectory in WorkspaceModule.ListDirectories(serviceDirectory)
|
||||
let workspaceApisDirectory = new WorkspaceApisDirectory { Parent = workspaceDirectory }
|
||||
where workspaceApisDirectory.ToDirectoryInfo().Exists()
|
||||
from workspaceApiDirectoryInfo in workspaceApisDirectory.ToDirectoryInfo().ListDirectories("*")
|
||||
let name = ApiName.From(workspaceApiDirectoryInfo.Name)
|
||||
select new WorkspaceApiDirectory
|
||||
{
|
||||
Parent = workspaceApisDirectory,
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static IEnumerable<WorkspaceApiInformationFile> ListInformationFiles(ManagementServiceDirectory serviceDirectory) =>
|
||||
from workspaceApiDirectory in ListDirectories(serviceDirectory)
|
||||
let informationFile = new WorkspaceApiInformationFile { Parent = workspaceApiDirectory }
|
||||
where informationFile.ToFileInfo().Exists()
|
||||
select informationFile;
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceApiInformationFile file, WorkspaceApiDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteSpecification(this WorkspaceApiSpecificationFile file, BinaryData contents, CancellationToken cancellationToken) =>
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(contents, cancellationToken);
|
||||
|
||||
public static async ValueTask<WorkspaceApiDto> ReadDto(this WorkspaceApiInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceApiDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceApiReleaseName : ResourceName
|
||||
{
|
||||
private WorkspaceApiReleaseName(string value) : base(value) { }
|
||||
|
||||
public static WorkspaceApiReleaseName From(string value) => new(value);
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiReleasesUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceApiUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "releases";
|
||||
|
||||
protected override Uri Value =>
|
||||
Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceApiReleasesUri From(ApiName apiName, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceApiUri.From(apiName, workspaceName, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiReleaseUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceApiReleasesUri Parent { get; init; }
|
||||
|
||||
public required WorkspaceApiReleaseName Name { get; init; }
|
||||
|
||||
protected override Uri Value =>
|
||||
Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceApiReleaseUri From(WorkspaceApiReleaseName name, ApiName apiName, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceApiReleasesUri.From(apiName, workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiReleasesDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceApiDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "releases";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceApiReleasesDirectory From(ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceApiDirectory.From(apiName, workspaceName, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceApiReleasesDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
directory?.Name == Name
|
||||
? from parent in WorkspaceApiDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceApiReleasesDirectory { Parent = parent }
|
||||
: Option<WorkspaceApiReleasesDirectory>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiReleaseDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceApiReleasesDirectory Parent { get; init; }
|
||||
|
||||
public required WorkspaceApiReleaseName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.Value);
|
||||
|
||||
public static WorkspaceApiReleaseDirectory From(WorkspaceApiReleaseName name, ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceApiReleasesDirectory.From(apiName, workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceApiReleaseDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceApiReleasesDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
let name = WorkspaceApiReleaseName.From(directory!.Name)
|
||||
select new WorkspaceApiReleaseDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiReleaseInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceApiReleaseDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "releaseInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceApiReleaseInformationFile From(WorkspaceApiReleaseName name, ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceApiReleaseDirectory.From(name, apiName, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceApiReleaseInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file?.Name == Name
|
||||
? from parent in WorkspaceApiReleaseDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceApiReleaseInformationFile
|
||||
{
|
||||
Parent = parent
|
||||
}
|
||||
: Option<WorkspaceApiReleaseInformationFile>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceApiReleaseDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required ApiReleaseContract Properties { get; init; }
|
||||
|
||||
public record ApiReleaseContract
|
||||
{
|
||||
[JsonPropertyName("apiId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ApiId { get; init; }
|
||||
|
||||
[JsonPropertyName("notes")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Notes { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceApiReleaseModule
|
||||
{
|
||||
public static async ValueTask DeleteAll(this WorkspaceApiReleasesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await uri.ListNames(pipeline, cancellationToken)
|
||||
.IterParallel(async name =>
|
||||
{
|
||||
var resourceUri = new WorkspaceApiReleaseUri { Parent = uri, Name = name };
|
||||
await resourceUri.Delete(pipeline, cancellationToken);
|
||||
}, cancellationToken);
|
||||
|
||||
public static IAsyncEnumerable<WorkspaceApiReleaseName> ListNames(this WorkspaceApiReleasesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(WorkspaceApiReleaseName.From);
|
||||
|
||||
public static IAsyncEnumerable<(WorkspaceApiReleaseName Name, WorkspaceApiReleaseDto Dto)> List(this WorkspaceApiReleasesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
uri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var resourceUri = new WorkspaceApiReleaseUri { Parent = uri, Name = name };
|
||||
var dto = await resourceUri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceApiReleaseDto> GetDto(this WorkspaceApiReleaseUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceApiReleaseDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceApiReleaseUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceApiReleaseUri uri, WorkspaceApiReleaseDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static IEnumerable<WorkspaceApiReleaseDirectory> ListDirectories(ManagementServiceDirectory serviceDirectory) =>
|
||||
from workspaceApiDirectory in WorkspaceApiModule.ListDirectories(serviceDirectory)
|
||||
let workspaceApiReleasesDirectory = new WorkspaceApiReleasesDirectory { Parent = workspaceApiDirectory }
|
||||
where workspaceApiReleasesDirectory.ToDirectoryInfo().Exists()
|
||||
from workspaceApiReleaseDirectoryInfo in workspaceApiReleasesDirectory.ToDirectoryInfo().ListDirectories("*")
|
||||
let name = WorkspaceApiReleaseName.From(workspaceApiReleaseDirectoryInfo.Name)
|
||||
select new WorkspaceApiReleaseDirectory
|
||||
{
|
||||
Parent = workspaceApiReleasesDirectory,
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static IEnumerable<WorkspaceApiReleaseInformationFile> ListInformationFiles(ManagementServiceDirectory serviceDirectory) =>
|
||||
from workspaceApiReleaseDirectory in ListDirectories(serviceDirectory)
|
||||
let informationFile = new WorkspaceApiReleaseInformationFile { Parent = workspaceApiReleaseDirectory }
|
||||
where informationFile.ToFileInfo().Exists()
|
||||
select informationFile;
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceApiReleaseInformationFile file, WorkspaceApiReleaseDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceApiReleaseDto> ReadDto(this WorkspaceApiReleaseInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceApiReleaseDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public abstract record WorkspaceApiSpecificationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceApiDirectory Parent { get; init; }
|
||||
public abstract ApiSpecification Specification { get; }
|
||||
|
||||
public static WorkspaceApiSpecificationFile From(ApiSpecification specification, ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
specification switch
|
||||
{
|
||||
ApiSpecification.GraphQl => WorkspaceGraphQlSpecificationFile.From(apiName, workspaceName, serviceDirectory),
|
||||
ApiSpecification.Wadl => WorkspaceWadlSpecificationFile.From(apiName, workspaceName, serviceDirectory),
|
||||
ApiSpecification.Wsdl => WorkspaceWsdlSpecificationFile.From(apiName, workspaceName, serviceDirectory),
|
||||
ApiSpecification.OpenApi openApi => WorkspaceOpenApiSpecificationFile.From(openApi, apiName, workspaceName, serviceDirectory),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
public static async ValueTask<Option<WorkspaceApiSpecificationFile>> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await TryParse(file,
|
||||
getFileContents: async file => await file.ReadAsBinaryData(cancellationToken),
|
||||
serviceDirectory,
|
||||
cancellationToken);
|
||||
|
||||
public static async ValueTask<Option<WorkspaceApiSpecificationFile>> TryParse(FileInfo? file, Func<FileInfo, ValueTask<BinaryData>> getFileContents, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var tryParseGraphQl = () => (from specificationFile in WorkspaceGraphQlSpecificationFile.TryParse(file, serviceDirectory)
|
||||
select specificationFile as WorkspaceApiSpecificationFile).AsTask();
|
||||
|
||||
var tryParseWadl = () => (from specificationFile in WorkspaceWadlSpecificationFile.TryParse(file, serviceDirectory)
|
||||
select specificationFile as WorkspaceApiSpecificationFile).AsTask();
|
||||
|
||||
var tryParseWsdl = () => (from specificationFile in WorkspaceWsdlSpecificationFile.TryParse(file, serviceDirectory)
|
||||
select specificationFile as WorkspaceApiSpecificationFile).AsTask();
|
||||
|
||||
var tryParseOpenApi = async () => from specificationFile in await WorkspaceOpenApiSpecificationFile.TryParse(file, getFileContents, serviceDirectory, cancellationToken)
|
||||
select specificationFile as WorkspaceApiSpecificationFile;
|
||||
|
||||
return await ImmutableArray.Create(tryParseGraphQl, tryParseWadl, tryParseWsdl, tryParseOpenApi)
|
||||
.Pick(async (f, cancellationToken) => await f(), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record WorkspaceGraphQlSpecificationFile : WorkspaceApiSpecificationFile
|
||||
{
|
||||
public override ApiSpecification Specification { get; } = new ApiSpecification.GraphQl();
|
||||
|
||||
public static string Name => "specification.graphql";
|
||||
|
||||
protected override FileInfo Value => new(Path.Combine(Parent.ToDirectoryInfo().FullName, Name));
|
||||
|
||||
public static WorkspaceGraphQlSpecificationFile From(ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceApiDirectory.From(apiName, workspaceName, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceGraphQlSpecificationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null && file.Name == Name
|
||||
? from parent in WorkspaceApiDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceGraphQlSpecificationFile { Parent = parent }
|
||||
: Option<WorkspaceGraphQlSpecificationFile>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceWadlSpecificationFile : WorkspaceApiSpecificationFile
|
||||
{
|
||||
public override ApiSpecification Specification { get; } = new ApiSpecification.Wadl();
|
||||
|
||||
public static string Name => "specification.wadl";
|
||||
|
||||
protected override FileInfo Value => new(Path.Combine(Parent.ToDirectoryInfo().FullName, Name));
|
||||
|
||||
public static WorkspaceWadlSpecificationFile From(ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceApiDirectory.From(apiName, workspaceName, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceWadlSpecificationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null && file.Name == Name
|
||||
? from parent in WorkspaceApiDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceWadlSpecificationFile { Parent = parent }
|
||||
: Option<WorkspaceWadlSpecificationFile>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceWsdlSpecificationFile : WorkspaceApiSpecificationFile
|
||||
{
|
||||
public override ApiSpecification Specification { get; } = new ApiSpecification.Wsdl();
|
||||
|
||||
public static string Name => "specification.wsdl";
|
||||
|
||||
protected override FileInfo Value => new(Path.Combine(Parent.ToDirectoryInfo().FullName, Name));
|
||||
|
||||
public static WorkspaceWsdlSpecificationFile From(ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceApiDirectory.From(apiName, workspaceName, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceWsdlSpecificationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null && file.Name == Name
|
||||
? from parent in WorkspaceApiDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceWsdlSpecificationFile { Parent = parent }
|
||||
: Option<WorkspaceWsdlSpecificationFile>.None;
|
||||
}
|
||||
|
||||
public abstract record WorkspaceOpenApiSpecificationFile : WorkspaceApiSpecificationFile
|
||||
{
|
||||
public abstract OpenApiFormat Format { get; }
|
||||
public required OpenApiVersion Version { get; init; }
|
||||
|
||||
public static WorkspaceOpenApiSpecificationFile From(ApiSpecification.OpenApi openApi, ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
openApi.Format switch
|
||||
{
|
||||
OpenApiFormat.Json => JsonWorkspaceOpenApiSpecificationFile.From(openApi.Version, apiName, workspaceName, serviceDirectory),
|
||||
OpenApiFormat.Yaml => YamlWorkspaceOpenApiSpecificationFile.From(openApi.Version, apiName, workspaceName, serviceDirectory),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
public static new async ValueTask<Option<WorkspaceOpenApiSpecificationFile>> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await TryParse(file,
|
||||
getFileContents: async file => await file.ReadAsBinaryData(cancellationToken),
|
||||
serviceDirectory,
|
||||
cancellationToken);
|
||||
|
||||
public static new async ValueTask<Option<WorkspaceOpenApiSpecificationFile>> TryParse(FileInfo? file, Func<FileInfo, ValueTask<BinaryData>> getFileContents, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var tryParseYaml = async () => from yaml in await YamlWorkspaceOpenApiSpecificationFile.TryParse(file, getFileContents, serviceDirectory, cancellationToken)
|
||||
select yaml as WorkspaceOpenApiSpecificationFile;
|
||||
|
||||
var tryParseJson = async () => from json in await JsonWorkspaceOpenApiSpecificationFile.TryParse(file, getFileContents, serviceDirectory, cancellationToken)
|
||||
select json as WorkspaceOpenApiSpecificationFile;
|
||||
|
||||
return await ImmutableArray.Create(tryParseYaml, tryParseJson)
|
||||
.Pick(async (f, cancellationToken) => await f(), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record YamlWorkspaceOpenApiSpecificationFile : WorkspaceOpenApiSpecificationFile
|
||||
{
|
||||
public override OpenApiFormat Format { get; } = new OpenApiFormat.Yaml();
|
||||
public override ApiSpecification Specification => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = Format,
|
||||
Version = Version
|
||||
};
|
||||
public static string Name { get; } = "specification.yaml";
|
||||
|
||||
protected override FileInfo Value => new(Path.Combine(Parent.ToDirectoryInfo().FullName, Name));
|
||||
|
||||
public static YamlWorkspaceOpenApiSpecificationFile From(OpenApiVersion version, ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceApiDirectory.From(apiName, workspaceName, serviceDirectory),
|
||||
Version = version
|
||||
};
|
||||
|
||||
public static new async ValueTask<Option<YamlWorkspaceOpenApiSpecificationFile>> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await TryParse(file,
|
||||
getFileContents: async file => await file.ReadAsBinaryData(cancellationToken),
|
||||
serviceDirectory,
|
||||
cancellationToken);
|
||||
|
||||
public static new async ValueTask<Option<YamlWorkspaceOpenApiSpecificationFile>> TryParse(FileInfo? file, Func<FileInfo, ValueTask<BinaryData>> getFileContents, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
file is not null && file.Name == Name
|
||||
? await WorkspaceApiDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
.BindTask(async parent => from version in await OpenApiVersion.TryParse(await getFileContents(file), cancellationToken)
|
||||
select new YamlWorkspaceOpenApiSpecificationFile
|
||||
{
|
||||
Parent = parent,
|
||||
Version = version
|
||||
})
|
||||
: Option<YamlWorkspaceOpenApiSpecificationFile>.None;
|
||||
}
|
||||
|
||||
public sealed record JsonWorkspaceOpenApiSpecificationFile : WorkspaceOpenApiSpecificationFile
|
||||
{
|
||||
public override OpenApiFormat Format { get; } = new OpenApiFormat.Json();
|
||||
public override ApiSpecification Specification => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = Format,
|
||||
Version = Version
|
||||
};
|
||||
|
||||
public static string Name { get; } = "specification.json";
|
||||
|
||||
protected override FileInfo Value => new(Path.Combine(Parent.ToDirectoryInfo().FullName, Name));
|
||||
|
||||
public static JsonWorkspaceOpenApiSpecificationFile From(OpenApiVersion version, ApiName apiName, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceApiDirectory.From(apiName, workspaceName, serviceDirectory),
|
||||
Version = version
|
||||
};
|
||||
|
||||
public static new async ValueTask<Option<JsonWorkspaceOpenApiSpecificationFile>> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await TryParse(file,
|
||||
getFileContents: async file => await file.ReadAsBinaryData(cancellationToken),
|
||||
serviceDirectory,
|
||||
cancellationToken);
|
||||
|
||||
public static new async ValueTask<Option<JsonWorkspaceOpenApiSpecificationFile>> TryParse(FileInfo? file, Func<FileInfo, ValueTask<BinaryData>> getFileContents, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
file is not null && file.Name == Name
|
||||
? await WorkspaceApiDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
.BindTask(async parent => from version in await OpenApiVersion.TryParse(await getFileContents(file), cancellationToken)
|
||||
select new JsonWorkspaceOpenApiSpecificationFile
|
||||
{
|
||||
Parent = parent,
|
||||
Version = version
|
||||
})
|
||||
: Option<JsonWorkspaceOpenApiSpecificationFile>.None;
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceBackendsUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "backends";
|
||||
|
||||
protected override Uri Value =>
|
||||
Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceBackendsUri From(WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(workspaceName, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceBackendUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceBackendsUri Parent { get; init; }
|
||||
|
||||
public required BackendName Name { get; init; }
|
||||
|
||||
protected override Uri Value =>
|
||||
Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceBackendUri From(BackendName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceBackendsUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceBackendsDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "backends";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceBackendsDirectory From(WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(workspaceName, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceBackendsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
directory?.Name == Name
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceBackendsDirectory { Parent = parent }
|
||||
: Option<WorkspaceBackendsDirectory>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceBackendDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceBackendsDirectory Parent { get; init; }
|
||||
|
||||
public required BackendName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.Value);
|
||||
|
||||
public static WorkspaceBackendDirectory From(BackendName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceBackendsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceBackendDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceBackendsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
let name = BackendName.From(directory!.Name)
|
||||
select new WorkspaceBackendDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceBackendInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceBackendDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "backendInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceBackendInformationFile From(BackendName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceBackendDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceBackendInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file?.Name == Name
|
||||
? from parent in WorkspaceBackendDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceBackendInformationFile
|
||||
{
|
||||
Parent = parent
|
||||
}
|
||||
: Option<WorkspaceBackendInformationFile>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceBackendDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required BackendContract Properties { get; init; }
|
||||
|
||||
public record BackendContract
|
||||
{
|
||||
[JsonPropertyName("credentials")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public BackendCredentialsContract? Credentials { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public BackendProperties? Properties { get; init; }
|
||||
|
||||
[JsonPropertyName("protocol")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Protocol { get; init; }
|
||||
|
||||
[JsonPropertyName("proxy")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public BackendProxyContract? Proxy { get; init; }
|
||||
|
||||
[JsonPropertyName("resourceId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ResourceId { get; init; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Title { get; init; }
|
||||
|
||||
[JsonPropertyName("tls")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public BackendTlsProperties? Tls { get; init; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
#pragma warning disable CA1056 // URI-like properties should not be strings
|
||||
public string? Url { get; init; }
|
||||
#pragma warning restore CA1056 // URI-like properties should not be strings
|
||||
}
|
||||
|
||||
public record BackendCredentialsContract
|
||||
{
|
||||
[JsonPropertyName("authorization")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public BackendAuthorizationHeaderCredentials? Authorization { get; init; }
|
||||
|
||||
[JsonPropertyName("certificate")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableList<string>? Certificate { get; init; }
|
||||
|
||||
[JsonPropertyName("certificateIds")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableList<string>? CertificateIds { get; init; }
|
||||
|
||||
[JsonPropertyName("header")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public JsonObject? Header { get; init; }
|
||||
|
||||
[JsonPropertyName("query")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public JsonObject? Query { get; init; }
|
||||
}
|
||||
|
||||
public record BackendAuthorizationHeaderCredentials
|
||||
{
|
||||
[JsonPropertyName("parameter")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Parameter { get; init; }
|
||||
|
||||
[JsonPropertyName("scheme")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Scheme { get; init; }
|
||||
}
|
||||
|
||||
public record BackendProperties
|
||||
{
|
||||
[JsonPropertyName("serviceFabricCluster")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public BackendServiceFabricClusterProperties? ServiceFabricCluster { get; init; }
|
||||
}
|
||||
|
||||
public record BackendProxyContract
|
||||
{
|
||||
[JsonPropertyName("password")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Password { get; init; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
#pragma warning disable CA1056 // URI-like properties should not be strings
|
||||
public string? Url { get; init; }
|
||||
|
||||
#pragma warning restore CA1056 // URI-like properties should not be strings
|
||||
[JsonPropertyName("username")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Username { get; init; }
|
||||
}
|
||||
|
||||
public record BackendServiceFabricClusterProperties
|
||||
{
|
||||
[JsonPropertyName("clientCertificateId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ClientCertificateId { get; init; }
|
||||
|
||||
[JsonPropertyName("clientCertificatethumbprint")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ClientCertificateThumbprint { get; init; }
|
||||
|
||||
[JsonPropertyName("managementEndpoints")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableList<string>? ManagementEndpoints { get; init; }
|
||||
|
||||
[JsonPropertyName("maxPartitionResolutionRetries")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? MaxPartitionResolutionRetries { get; init; }
|
||||
|
||||
[JsonPropertyName("serverCertificateThumbprints")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableList<string>? ServerCertificateThumbprints { get; init; }
|
||||
|
||||
[JsonPropertyName("serverX509Names")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableList<X509CertificateName>? ServerX509Names { get; init; }
|
||||
}
|
||||
|
||||
public record BackendTlsProperties
|
||||
{
|
||||
[JsonPropertyName("validateCertificateChain")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? ValidateCertificateChain { get; init; }
|
||||
|
||||
[JsonPropertyName("validateCertificateName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? ValidateCertificateName { get; init; }
|
||||
}
|
||||
|
||||
public record X509CertificateName
|
||||
{
|
||||
[JsonPropertyName("issuerCertificateThumbprint")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? IssuerCertificateThumbprint { get; init; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Name { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceBackendModule
|
||||
{
|
||||
public static async ValueTask DeleteAll(this WorkspaceBackendsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await uri.ListNames(pipeline, cancellationToken)
|
||||
.IterParallel(async name =>
|
||||
{
|
||||
var resourceUri = new WorkspaceBackendUri { Parent = uri, Name = name };
|
||||
await resourceUri.Delete(pipeline, cancellationToken);
|
||||
}, cancellationToken);
|
||||
|
||||
public static IAsyncEnumerable<BackendName> ListNames(this WorkspaceBackendsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(BackendName.From);
|
||||
|
||||
public static IAsyncEnumerable<(BackendName Name, WorkspaceBackendDto Dto)> List(this WorkspaceBackendsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
uri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var resourceUri = new WorkspaceBackendUri { Parent = uri, Name = name };
|
||||
var dto = await resourceUri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceBackendDto> GetDto(this WorkspaceBackendUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceBackendDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceBackendUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceBackendUri uri, WorkspaceBackendDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static IEnumerable<WorkspaceBackendDirectory> ListDirectories(ManagementServiceDirectory serviceDirectory) =>
|
||||
from workspaceDirectory in WorkspaceModule.ListDirectories(serviceDirectory)
|
||||
let workspacebackendsDirectory = new WorkspaceBackendsDirectory { Parent = workspaceDirectory }
|
||||
where workspacebackendsDirectory.ToDirectoryInfo().Exists()
|
||||
from workspaceBackendDirectoryInfo in workspacebackendsDirectory.ToDirectoryInfo().ListDirectories("*")
|
||||
let name = BackendName.From(workspaceBackendDirectoryInfo.Name)
|
||||
select new WorkspaceBackendDirectory
|
||||
{
|
||||
Parent = workspacebackendsDirectory,
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static IEnumerable<WorkspaceBackendInformationFile> ListInformationFiles(ManagementServiceDirectory serviceDirectory) =>
|
||||
from workspaceBackendDirectory in ListDirectories(serviceDirectory)
|
||||
let informationFile = new WorkspaceBackendInformationFile { Parent = workspaceBackendDirectory }
|
||||
where informationFile.ToFileInfo().Exists()
|
||||
select informationFile;
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceBackendInformationFile file, WorkspaceBackendDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceBackendDto> ReadDto(this WorkspaceBackendInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceBackendDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceDiagnosticsUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "diagnostics";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceDiagnosticsUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceDiagnosticUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceDiagnosticsUri Parent { get; init; }
|
||||
public required DiagnosticName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceDiagnosticUri From(DiagnosticName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceDiagnosticsUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceDiagnosticsDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "diagnostics";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceDiagnosticsDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceDiagnosticsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceDiagnosticsDirectory { Parent = parent }
|
||||
: Option<WorkspaceDiagnosticsDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceDiagnosticDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDiagnosticsDirectory Parent { get; init; }
|
||||
|
||||
public required DiagnosticName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspaceDiagnosticDirectory From(DiagnosticName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceDiagnosticsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceDiagnosticDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceDiagnosticsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspaceDiagnosticDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = DiagnosticName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceDiagnosticInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceDiagnosticDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "diagnosticInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceDiagnosticInformationFile From(DiagnosticName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceDiagnosticDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceDiagnosticInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspaceDiagnosticDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceDiagnosticInformationFile { Parent = parent }
|
||||
: Option<WorkspaceDiagnosticInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceDiagnosticDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required DiagnosticContract Properties { get; init; }
|
||||
|
||||
public sealed record DiagnosticContract
|
||||
{
|
||||
[JsonPropertyName("loggerId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? LoggerId { get; init; }
|
||||
|
||||
[JsonPropertyName("alwaysLog")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? AlwaysLog { get; init; }
|
||||
|
||||
[JsonPropertyName("backend")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public PipelineDiagnosticSettings? Backend { get; init; }
|
||||
|
||||
[JsonPropertyName("frontend")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public PipelineDiagnosticSettings? Frontend { get; init; }
|
||||
|
||||
[JsonPropertyName("httpCorrelationProtocol")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? HttpCorrelationProtocol { get; init; }
|
||||
|
||||
[JsonPropertyName("logClientIp")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? LogClientIp { get; init; }
|
||||
|
||||
[JsonPropertyName("metrics")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? Metrics { get; init; }
|
||||
|
||||
[JsonPropertyName("operationNameFormat")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? OperationNameFormat { get; init; }
|
||||
|
||||
[JsonPropertyName("sampling")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public SamplingSettings? Sampling { get; init; }
|
||||
|
||||
[JsonPropertyName("verbosity")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Verbosity { get; init; }
|
||||
}
|
||||
|
||||
public sealed record PipelineDiagnosticSettings
|
||||
{
|
||||
[JsonPropertyName("request")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public HttpMessageDiagnostic? Request { get; init; }
|
||||
|
||||
[JsonPropertyName("response")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public HttpMessageDiagnostic? Response { get; init; }
|
||||
}
|
||||
|
||||
public sealed record HttpMessageDiagnostic
|
||||
{
|
||||
[JsonPropertyName("body")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public BodyDiagnosticSettings? Body { get; init; }
|
||||
|
||||
[JsonPropertyName("dataMasking")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DataMasking? DataMasking { get; init; }
|
||||
|
||||
[JsonPropertyName("headers")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableArray<string>? Headers { get; init; }
|
||||
}
|
||||
|
||||
public sealed record BodyDiagnosticSettings
|
||||
{
|
||||
[JsonPropertyName("bytes")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? Bytes { get; init; }
|
||||
}
|
||||
|
||||
public sealed record DataMasking
|
||||
{
|
||||
[JsonPropertyName("headers")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableArray<DataMaskingEntity>? Headers { get; init; }
|
||||
|
||||
[JsonPropertyName("queryParams")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableArray<DataMaskingEntity>? QueryParams { get; init; }
|
||||
}
|
||||
|
||||
public sealed record DataMaskingEntity
|
||||
{
|
||||
[JsonPropertyName("mode")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Mode { get; init; }
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Value { get; init; }
|
||||
}
|
||||
|
||||
public sealed record SamplingSettings
|
||||
{
|
||||
[JsonPropertyName("percentage")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public float? Percentage { get; init; }
|
||||
|
||||
[JsonPropertyName("samplingType")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? SamplingType { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceDiagnosticModule
|
||||
{
|
||||
public static IAsyncEnumerable<DiagnosticName> ListNames(this WorkspaceDiagnosticsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(DiagnosticName.From);
|
||||
|
||||
public static IAsyncEnumerable<(DiagnosticName Name, WorkspaceDiagnosticDto Dto)> List(this WorkspaceDiagnosticsUri workspaceDiagnosticsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspaceDiagnosticsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspaceDiagnosticUri { Parent = workspaceDiagnosticsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceDiagnosticDto> GetDto(this WorkspaceDiagnosticUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceDiagnosticDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceDiagnosticUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceDiagnosticUri uri, WorkspaceDiagnosticDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceDiagnosticInformationFile file, WorkspaceDiagnosticDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceDiagnosticDto> ReadDto(this WorkspaceDiagnosticInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceDiagnosticDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceGroupsUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "groups";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceGroupsUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceGroupUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceGroupsUri Parent { get; init; }
|
||||
public required GroupName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceGroupUri From(GroupName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceGroupsUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceGroupsDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "groups";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceGroupsDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceGroupsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceGroupsDirectory { Parent = parent }
|
||||
: Option<WorkspaceGroupsDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceGroupDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceGroupsDirectory Parent { get; init; }
|
||||
|
||||
public required GroupName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspaceGroupDirectory From(GroupName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceGroupsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceGroupDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceGroupsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspaceGroupDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = GroupName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceGroupInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceGroupDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "groupInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceGroupInformationFile From(GroupName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceGroupDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceGroupInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspaceGroupDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceGroupInformationFile { Parent = parent }
|
||||
: Option<WorkspaceGroupInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceGroupDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required GroupContract Properties { get; init; }
|
||||
|
||||
public sealed record GroupContract
|
||||
{
|
||||
[JsonPropertyName("displayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? DisplayName { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("externalId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ExternalId { get; init; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Type { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceGroupModule
|
||||
{
|
||||
public static IAsyncEnumerable<GroupName> ListNames(this WorkspaceGroupsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(GroupName.From);
|
||||
|
||||
public static IAsyncEnumerable<(GroupName Name, WorkspaceGroupDto Dto)> List(this WorkspaceGroupsUri workspaceGroupsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspaceGroupsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspaceGroupUri { Parent = workspaceGroupsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceGroupDto> GetDto(this WorkspaceGroupUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceGroupDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceGroupUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceGroupUri uri, WorkspaceGroupDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceGroupInformationFile file, WorkspaceGroupDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceGroupDto> ReadDto(this WorkspaceGroupInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceGroupDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceLoggersUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "loggers";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceLoggersUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceLoggerUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceLoggersUri Parent { get; init; }
|
||||
public required LoggerName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceLoggerUri From(LoggerName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceLoggersUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceLoggersDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "loggers";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceLoggersDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceLoggersDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceLoggersDirectory { Parent = parent }
|
||||
: Option<WorkspaceLoggersDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceLoggerDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceLoggersDirectory Parent { get; init; }
|
||||
|
||||
public required LoggerName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspaceLoggerDirectory From(LoggerName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceLoggersDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceLoggerDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceLoggersDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspaceLoggerDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = LoggerName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceLoggerInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceLoggerDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "loggerInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceLoggerInformationFile From(LoggerName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceLoggerDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceLoggerInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspaceLoggerDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceLoggerInformationFile { Parent = parent }
|
||||
: Option<WorkspaceLoggerInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceLoggerDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required LoggerContract Properties { get; init; }
|
||||
|
||||
public record LoggerContract
|
||||
{
|
||||
[JsonPropertyName("loggerType")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? LoggerType { get; init; }
|
||||
|
||||
[JsonPropertyName("credentials")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public JsonObject? Credentials { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("isBuffered")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? IsBuffered { get; init; }
|
||||
|
||||
[JsonPropertyName("resourceId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? ResourceId { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceLoggerModule
|
||||
{
|
||||
public static IAsyncEnumerable<LoggerName> ListNames(this WorkspaceLoggersUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(LoggerName.From);
|
||||
|
||||
public static IAsyncEnumerable<(LoggerName Name, WorkspaceLoggerDto Dto)> List(this WorkspaceLoggersUri workspaceLoggersUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspaceLoggersUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspaceLoggerUri { Parent = workspaceLoggersUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceLoggerDto> GetDto(this WorkspaceLoggerUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceLoggerDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceLoggerUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceLoggerUri uri, WorkspaceLoggerDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceLoggerInformationFile file, WorkspaceLoggerDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceLoggerDto> ReadDto(this WorkspaceLoggerInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceLoggerDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceNamedValuesUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "namedValues";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceNamedValuesUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceNamedValueUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceNamedValuesUri Parent { get; init; }
|
||||
public required NamedValueName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceNamedValueUri From(NamedValueName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceNamedValuesUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceNamedValuesDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "named values";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceNamedValuesDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceNamedValuesDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceNamedValuesDirectory { Parent = parent }
|
||||
: Option<WorkspaceNamedValuesDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceNamedValueDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceNamedValuesDirectory Parent { get; init; }
|
||||
|
||||
public required NamedValueName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspaceNamedValueDirectory From(NamedValueName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceNamedValuesDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceNamedValueDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceNamedValuesDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspaceNamedValueDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = NamedValueName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceNamedValueInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceNamedValueDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "namedValueInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceNamedValueInformationFile From(NamedValueName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceNamedValueDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceNamedValueInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspaceNamedValueDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceNamedValueInformationFile { Parent = parent }
|
||||
: Option<WorkspaceNamedValueInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceNamedValueDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required NamedValueContract Properties { get; init; }
|
||||
|
||||
public sealed record NamedValueContract
|
||||
{
|
||||
[JsonPropertyName("displayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? DisplayName { get; init; }
|
||||
|
||||
[JsonPropertyName("keyVault")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public KeyVaultContract? KeyVault { get; init; }
|
||||
|
||||
[JsonPropertyName("secret")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? Secret { get; init; }
|
||||
|
||||
[JsonPropertyName("tags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public ImmutableArray<string>? Tags { get; init; }
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Value { get; init; }
|
||||
}
|
||||
|
||||
public sealed record KeyVaultContract
|
||||
{
|
||||
[JsonPropertyName("identityClientId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? IdentityClientId { get; init; }
|
||||
|
||||
[JsonPropertyName("secretIdentifier")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? SecretIdentifier { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceNamedValueModule
|
||||
{
|
||||
public static IAsyncEnumerable<NamedValueName> ListNames(this WorkspaceNamedValuesUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(NamedValueName.From);
|
||||
|
||||
public static IAsyncEnumerable<(NamedValueName Name, WorkspaceNamedValueDto Dto)> List(this WorkspaceNamedValuesUri workspaceNamedValuesUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspaceNamedValuesUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspaceNamedValueUri { Parent = workspaceNamedValuesUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceNamedValueDto> GetDto(this WorkspaceNamedValueUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceNamedValueDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceNamedValueUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceNamedValueUri uri, WorkspaceNamedValueDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceNamedValueInformationFile file, WorkspaceNamedValueDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceNamedValueDto> ReadDto(this WorkspaceNamedValueInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceNamedValueDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspacePolicyName : ResourceName
|
||||
{
|
||||
private WorkspacePolicyName(string value) : base(value) { }
|
||||
|
||||
public static WorkspacePolicyName From(string value) => new(value);
|
||||
}
|
||||
|
||||
public sealed record WorkspacePoliciesUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "policies";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspacePoliciesUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyUri : ResourceUri
|
||||
{
|
||||
public required WorkspacePoliciesUri Parent { get; init; }
|
||||
public required WorkspacePolicyName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspacePolicyUri From(WorkspacePolicyName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspacePoliciesUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
public required WorkspacePolicyName Name { get; init; }
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile($"{Name}.xml");
|
||||
|
||||
public static WorkspacePolicyFile From(WorkspacePolicyName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspacePolicyFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
from name in TryParseWorkspacePolicyName(file)
|
||||
from parent in WorkspaceDirectory.TryParse(file?.Directory, serviceDirectory)
|
||||
select new WorkspacePolicyFile
|
||||
{
|
||||
Name = name,
|
||||
Parent = parent
|
||||
};
|
||||
|
||||
internal static Option<WorkspacePolicyName> TryParseWorkspacePolicyName(FileInfo? file) =>
|
||||
file?.Name.EndsWith(".xml", StringComparison.Ordinal) switch
|
||||
{
|
||||
true => WorkspacePolicyName.From(Path.GetFileNameWithoutExtension(file.Name)),
|
||||
_ => Option<WorkspacePolicyName>.None
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required WorkspacePolicyContract Properties { get; init; }
|
||||
|
||||
public sealed record WorkspacePolicyContract
|
||||
{
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("format")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Format { get; init; }
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Value { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspacePolicyModule
|
||||
{
|
||||
public static async IAsyncEnumerable<WorkspacePolicyName> ListNames(this WorkspacePoliciesUri uri, HttpPipeline pipeline, [EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
// The REST API call to list policy names returns incorrectly formatted names.
|
||||
// For now, we'll return the single policy named "policy" if it exists
|
||||
var policyName = WorkspacePolicyName.From("policy");
|
||||
var policyUri = uri.ToUri().AppendPathSegment(policyName.Value).ToUri();
|
||||
|
||||
var option = await pipeline.GetJsonObjectOption(policyUri, cancellationToken);
|
||||
|
||||
if (option.IsSome)
|
||||
{
|
||||
yield return policyName;
|
||||
}
|
||||
}
|
||||
|
||||
public static IAsyncEnumerable<(WorkspacePolicyName Name, WorkspacePolicyDto Dto)> List(this WorkspacePoliciesUri workspacePoliciesUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspacePoliciesUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspacePolicyUri { Parent = workspacePoliciesUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspacePolicyDto> GetDto(this WorkspacePolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var contentUri = uri.ToUri().AppendQueryParam("format", "rawxml").ToUri();
|
||||
var content = await pipeline.GetContent(contentUri, cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspacePolicyDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspacePolicyUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspacePolicyUri uri, WorkspacePolicyDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static IEnumerable<WorkspacePolicyFile> ListPolicyFiles(WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
var workspaceDirectory = WorkspaceDirectory.From(workspaceName, serviceDirectory);
|
||||
|
||||
return workspaceDirectory.ToDirectoryInfo()
|
||||
.ListFiles("*")
|
||||
.Choose(WorkspacePolicyFile.TryParseWorkspacePolicyName)
|
||||
.Select(name => new WorkspacePolicyFile { Name = name, Parent = workspaceDirectory });
|
||||
}
|
||||
|
||||
public static async ValueTask WritePolicy(this WorkspacePolicyFile file, string policy, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromString(policy);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<string> ReadPolicy(this WorkspacePolicyFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspacePolicyFragmentsUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "policyFragments";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspacePolicyFragmentsUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyFragmentUri : ResourceUri
|
||||
{
|
||||
public required WorkspacePolicyFragmentsUri Parent { get; init; }
|
||||
public required PolicyFragmentName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspacePolicyFragmentUri From(PolicyFragmentName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspacePolicyFragmentsUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyFragmentsDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "policy fragments";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspacePolicyFragmentsDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspacePolicyFragmentsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspacePolicyFragmentsDirectory { Parent = parent }
|
||||
: Option<WorkspacePolicyFragmentsDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyFragmentDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspacePolicyFragmentsDirectory Parent { get; init; }
|
||||
|
||||
public required PolicyFragmentName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspacePolicyFragmentDirectory From(PolicyFragmentName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspacePolicyFragmentsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspacePolicyFragmentDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspacePolicyFragmentsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspacePolicyFragmentDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = PolicyFragmentName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyFragmentInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspacePolicyFragmentDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "policyFragmentInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspacePolicyFragmentInformationFile From(PolicyFragmentName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspacePolicyFragmentDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspacePolicyFragmentInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspacePolicyFragmentDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspacePolicyFragmentInformationFile { Parent = parent }
|
||||
: Option<WorkspacePolicyFragmentInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyFragmentPolicyFile : ResourceFile
|
||||
{
|
||||
public required WorkspacePolicyFragmentDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "policy.xml";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspacePolicyFragmentPolicyFile From(PolicyFragmentName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = new WorkspacePolicyFragmentDirectory
|
||||
{
|
||||
Parent = WorkspacePolicyFragmentsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
}
|
||||
};
|
||||
|
||||
public static Option<WorkspacePolicyFragmentPolicyFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
file is not null && file.Name == Name
|
||||
? from parent in WorkspacePolicyFragmentDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspacePolicyFragmentPolicyFile { Parent = parent }
|
||||
: Option<WorkspacePolicyFragmentPolicyFile>.None;
|
||||
}
|
||||
|
||||
public sealed record WorkspacePolicyFragmentDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required PolicyFragmentContract Properties { get; init; }
|
||||
|
||||
public sealed record PolicyFragmentContract
|
||||
{
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("format")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Format { get; init; }
|
||||
|
||||
[JsonPropertyName("value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Value { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspacePolicyFragmentModule
|
||||
{
|
||||
public static IAsyncEnumerable<PolicyFragmentName> ListNames(this WorkspacePolicyFragmentsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(PolicyFragmentName.From);
|
||||
|
||||
public static IAsyncEnumerable<(PolicyFragmentName Name, WorkspacePolicyFragmentDto Dto)> List(this WorkspacePolicyFragmentsUri workspacePolicyFragmentsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspacePolicyFragmentsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspacePolicyFragmentUri { Parent = workspacePolicyFragmentsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspacePolicyFragmentDto> GetDto(this WorkspacePolicyFragmentUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var contentUri = uri.ToUri().AppendQueryParam("format", "rawxml").ToUri();
|
||||
var content = await pipeline.GetContent(contentUri, cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspacePolicyFragmentDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspacePolicyFragmentUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspacePolicyFragmentUri uri, WorkspacePolicyFragmentDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspacePolicyFragmentInformationFile file, WorkspacePolicyFragmentDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspacePolicyFragmentDto> ReadDto(this WorkspacePolicyFragmentInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspacePolicyFragmentDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask WritePolicy(this WorkspacePolicyFragmentPolicyFile file, string policy, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromString(policy);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceProductsUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "products";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceProductsUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceProductUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceProductsUri Parent { get; init; }
|
||||
public required ProductName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceProductUri From(ProductName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceProductsUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceProductsDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "products";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceProductsDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceProductsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceProductsDirectory { Parent = parent }
|
||||
: Option<WorkspaceProductsDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceProductDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceProductsDirectory Parent { get; init; }
|
||||
|
||||
public required ProductName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspaceProductDirectory From(ProductName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceProductsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceProductDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceProductsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspaceProductDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = ProductName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceProductInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceProductDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "productInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceProductInformationFile From(ProductName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceProductDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceProductInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspaceProductDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceProductInformationFile { Parent = parent }
|
||||
: Option<WorkspaceProductInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceProductDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required ProductContract Properties { get; init; }
|
||||
|
||||
public record ProductContract
|
||||
{
|
||||
[JsonPropertyName("displayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? DisplayName { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("approvalRequired")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? ApprovalRequired { get; init; }
|
||||
|
||||
[JsonPropertyName("state")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? State { get; init; }
|
||||
|
||||
[JsonPropertyName("subscriptionRequired")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? SubscriptionRequired { get; init; }
|
||||
|
||||
[JsonPropertyName("subscriptionsLimit")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? SubscriptionsLimit { get; init; }
|
||||
|
||||
[JsonPropertyName("terms")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Terms { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceProductModule
|
||||
{
|
||||
public static IAsyncEnumerable<ProductName> ListNames(this WorkspaceProductsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(ProductName.From);
|
||||
|
||||
public static IAsyncEnumerable<(ProductName Name, WorkspaceProductDto Dto)> List(this WorkspaceProductsUri workspaceProductsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspaceProductsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspaceProductUri { Parent = workspaceProductsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceProductDto> GetDto(this WorkspaceProductUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceProductDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceProductUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceProductUri uri, WorkspaceProductDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceProductInformationFile file, WorkspaceProductDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceProductDto> ReadDto(this WorkspaceProductInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceProductDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceSubscriptionsUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "subscriptions";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceSubscriptionsUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceSubscriptionUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceSubscriptionsUri Parent { get; init; }
|
||||
public required SubscriptionName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceSubscriptionUri From(SubscriptionName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceSubscriptionsUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceSubscriptionsDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "subscriptions";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceSubscriptionsDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceSubscriptionsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceSubscriptionsDirectory { Parent = parent }
|
||||
: Option<WorkspaceSubscriptionsDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceSubscriptionDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceSubscriptionsDirectory Parent { get; init; }
|
||||
|
||||
public required SubscriptionName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspaceSubscriptionDirectory From(SubscriptionName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceSubscriptionsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceSubscriptionDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceSubscriptionsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspaceSubscriptionDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = SubscriptionName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceSubscriptionInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceSubscriptionDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "subscriptionInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceSubscriptionInformationFile From(SubscriptionName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceSubscriptionDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceSubscriptionInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspaceSubscriptionDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceSubscriptionInformationFile { Parent = parent }
|
||||
: Option<WorkspaceSubscriptionInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceSubscriptionDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required SubscriptionContract Properties { get; init; }
|
||||
|
||||
public sealed record SubscriptionContract
|
||||
{
|
||||
[JsonPropertyName("displayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? DisplayName { get; init; }
|
||||
|
||||
[JsonPropertyName("scope")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Scope { get; init; }
|
||||
|
||||
[JsonPropertyName("allowTracing")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? AllowTracing { get; init; }
|
||||
|
||||
[JsonPropertyName("ownerId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? OwnerId { get; init; }
|
||||
|
||||
[JsonPropertyName("primaryKey")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? PrimaryKey { get; init; }
|
||||
|
||||
[JsonPropertyName("secondaryKey")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? SecondaryKey { get; init; }
|
||||
|
||||
[JsonPropertyName("state")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? State { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceSubscriptionModule
|
||||
{
|
||||
public static IAsyncEnumerable<SubscriptionName> ListNames(this WorkspaceSubscriptionsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(SubscriptionName.From);
|
||||
|
||||
public static IAsyncEnumerable<(SubscriptionName Name, WorkspaceSubscriptionDto Dto)> List(this WorkspaceSubscriptionsUri workspaceSubscriptionsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspaceSubscriptionsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspaceSubscriptionUri { Parent = workspaceSubscriptionsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceSubscriptionDto> GetDto(this WorkspaceSubscriptionUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceSubscriptionDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceSubscriptionUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceSubscriptionUri uri, WorkspaceSubscriptionDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceSubscriptionInformationFile file, WorkspaceSubscriptionDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceSubscriptionDto> ReadDto(this WorkspaceSubscriptionInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceSubscriptionDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceTagsUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "tags";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceTagsUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceTagUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceTagsUri Parent { get; init; }
|
||||
public required TagName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceTagUri From(TagName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceTagsUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceTagsDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "tags";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceTagsDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceTagsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceTagsDirectory { Parent = parent }
|
||||
: Option<WorkspaceTagsDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceTagDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceTagsDirectory Parent { get; init; }
|
||||
|
||||
public required TagName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspaceTagDirectory From(TagName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceTagsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceTagDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceTagsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspaceTagDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = TagName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceTagInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceTagDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "tagInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceTagInformationFile From(TagName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceTagDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceTagInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspaceTagDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceTagInformationFile { Parent = parent }
|
||||
: Option<WorkspaceTagInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceTagDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required TagContract Properties { get; init; }
|
||||
|
||||
public sealed record TagContract
|
||||
{
|
||||
[JsonPropertyName("displayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? DisplayName { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceTagModule
|
||||
{
|
||||
public static IAsyncEnumerable<TagName> ListNames(this WorkspaceTagsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(TagName.From);
|
||||
|
||||
public static IAsyncEnumerable<(TagName Name, WorkspaceTagDto Dto)> List(this WorkspaceTagsUri workspaceTagsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspaceTagsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspaceTagUri { Parent = workspaceTagsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceTagDto> GetDto(this WorkspaceTagUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceTagDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceTagUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceTagUri uri, WorkspaceTagDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceTagInformationFile file, WorkspaceTagDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceTagDto> ReadDto(this WorkspaceTagInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceTagDto>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace common;
|
||||
|
||||
public sealed record WorkspaceVersionSetsUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceUri Parent { get; init; }
|
||||
|
||||
private static string PathSegment { get; } = "apiVersionSets";
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(PathSegment).ToUri();
|
||||
|
||||
public static WorkspaceVersionSetsUri From(WorkspaceName name, ManagementServiceUri serviceUri) =>
|
||||
new() { Parent = WorkspaceUri.From(name, serviceUri) };
|
||||
}
|
||||
|
||||
public sealed record WorkspaceVersionSetUri : ResourceUri
|
||||
{
|
||||
public required WorkspaceVersionSetsUri Parent { get; init; }
|
||||
public required VersionSetName Name { get; init; }
|
||||
|
||||
protected override Uri Value => Parent.ToUri().AppendPathSegment(Name.ToString()).ToUri();
|
||||
|
||||
public static WorkspaceVersionSetUri From(VersionSetName name, WorkspaceName workspaceName, ManagementServiceUri serviceUri) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceVersionSetsUri.From(workspaceName, serviceUri),
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceVersionSetsDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceDirectory Parent { get; init; }
|
||||
private static string Name { get; } = "version sets";
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name);
|
||||
|
||||
public static WorkspaceVersionSetsDirectory From(WorkspaceName name, ManagementServiceDirectory serviceDirectory) =>
|
||||
new() { Parent = WorkspaceDirectory.From(name, serviceDirectory) };
|
||||
|
||||
public static Option<WorkspaceVersionSetsDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsDirectoryNameValid(directory)
|
||||
? from parent in WorkspaceDirectory.TryParse(directory.Parent, serviceDirectory)
|
||||
select new WorkspaceVersionSetsDirectory { Parent = parent }
|
||||
: Option<WorkspaceVersionSetsDirectory>.None;
|
||||
|
||||
internal static bool IsDirectoryNameValid([NotNullWhen(true)] DirectoryInfo? directory) =>
|
||||
directory?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceVersionSetDirectory : ResourceDirectory
|
||||
{
|
||||
public required WorkspaceVersionSetsDirectory Parent { get; init; }
|
||||
|
||||
public required VersionSetName Name { get; init; }
|
||||
|
||||
protected override DirectoryInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildDirectory(Name.ToString());
|
||||
|
||||
public static WorkspaceVersionSetDirectory From(VersionSetName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceVersionSetsDirectory.From(workspaceName, serviceDirectory),
|
||||
Name = name
|
||||
};
|
||||
|
||||
public static Option<WorkspaceVersionSetDirectory> TryParse(DirectoryInfo? directory, ManagementServiceDirectory serviceDirectory) =>
|
||||
from parent in WorkspaceVersionSetsDirectory.TryParse(directory?.Parent, serviceDirectory)
|
||||
select new WorkspaceVersionSetDirectory
|
||||
{
|
||||
Parent = parent,
|
||||
Name = VersionSetName.From(directory!.Name)
|
||||
};
|
||||
}
|
||||
|
||||
public sealed record WorkspaceVersionSetInformationFile : ResourceFile
|
||||
{
|
||||
public required WorkspaceVersionSetDirectory Parent { get; init; }
|
||||
|
||||
private static string Name { get; } = "versionSetInformation.json";
|
||||
|
||||
protected override FileInfo Value =>
|
||||
Parent.ToDirectoryInfo().GetChildFile(Name);
|
||||
|
||||
public static WorkspaceVersionSetInformationFile From(VersionSetName name, WorkspaceName workspaceName, ManagementServiceDirectory serviceDirectory) =>
|
||||
new()
|
||||
{
|
||||
Parent = WorkspaceVersionSetDirectory.From(name, workspaceName, serviceDirectory)
|
||||
};
|
||||
|
||||
public static Option<WorkspaceVersionSetInformationFile> TryParse(FileInfo? file, ManagementServiceDirectory serviceDirectory) =>
|
||||
IsFileNameValid(file)
|
||||
? from parent in WorkspaceVersionSetDirectory.TryParse(file.Directory, serviceDirectory)
|
||||
select new WorkspaceVersionSetInformationFile { Parent = parent }
|
||||
: Option<WorkspaceVersionSetInformationFile>.None;
|
||||
|
||||
internal static bool IsFileNameValid([NotNullWhen(true)] FileInfo? file) =>
|
||||
file?.Name == Name;
|
||||
}
|
||||
|
||||
public sealed record WorkspaceVersionSetDto
|
||||
{
|
||||
[JsonPropertyName("properties")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public required VersionSetContract Properties { get; init; }
|
||||
|
||||
public sealed record VersionSetContract
|
||||
{
|
||||
[JsonPropertyName("displayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? DisplayName { get; init; }
|
||||
|
||||
[JsonPropertyName("description")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? Description { get; init; }
|
||||
|
||||
[JsonPropertyName("versioningScheme")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? VersioningScheme { get; init; }
|
||||
|
||||
[JsonPropertyName("versionQueryName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? VersionQueryName { get; init; }
|
||||
|
||||
[JsonPropertyName("versionHeaderName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string? VersionHeaderName { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkspaceVersionSetModule
|
||||
{
|
||||
public static IAsyncEnumerable<VersionSetName> ListNames(this WorkspaceVersionSetsUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
pipeline.ListJsonObjects(uri.ToUri(), cancellationToken)
|
||||
.Select(jsonObject => jsonObject.GetStringProperty("name"))
|
||||
.Select(VersionSetName.From);
|
||||
|
||||
public static IAsyncEnumerable<(VersionSetName Name, WorkspaceVersionSetDto Dto)> List(this WorkspaceVersionSetsUri workspaceVersionSetsUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
workspaceVersionSetsUri.ListNames(pipeline, cancellationToken)
|
||||
.SelectAwait(async name =>
|
||||
{
|
||||
var uri = new WorkspaceVersionSetUri { Parent = workspaceVersionSetsUri, Name = name };
|
||||
var dto = await uri.GetDto(pipeline, cancellationToken);
|
||||
return (name, dto);
|
||||
});
|
||||
|
||||
public static async ValueTask<WorkspaceVersionSetDto> GetDto(this WorkspaceVersionSetUri uri, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await pipeline.GetContent(uri.ToUri(), cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceVersionSetDto>();
|
||||
}
|
||||
|
||||
public static async ValueTask Delete(this WorkspaceVersionSetUri uri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await pipeline.DeleteResource(uri.ToUri(), waitForCompletion: true, cancellationToken);
|
||||
|
||||
public static async ValueTask PutDto(this WorkspaceVersionSetUri uri, WorkspaceVersionSetDto dto, HttpPipeline pipeline, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto);
|
||||
await pipeline.PutContent(uri.ToUri(), content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask WriteDto(this WorkspaceVersionSetInformationFile file, WorkspaceVersionSetDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = BinaryData.FromObjectAsJson(dto, JsonObjectExtensions.SerializerOptions);
|
||||
await file.ToFileInfo().OverwriteWithBinaryData(content, cancellationToken);
|
||||
}
|
||||
|
||||
public static async ValueTask<WorkspaceVersionSetDto> ReadDto(this WorkspaceVersionSetInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var content = await file.ToFileInfo().ReadAsBinaryData(cancellationToken);
|
||||
return content.ToObjectFromJson<WorkspaceVersionSetDto>();
|
||||
}
|
||||
}
|
|
@ -10,27 +10,29 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.Core" Version="1.40.0" />
|
||||
<PackageReference Include="Azure.Core" Version="1.41.0" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.12.0" />
|
||||
<PackageReference Include="Azure.ResourceManager" Version="1.12.0" />
|
||||
<PackageReference Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.2.0" />
|
||||
<PackageReference Include="Azure.ResourceManager" Version="1.12.0" />
|
||||
<PackageReference Include="Flurl" Version="4.0.0" />
|
||||
<PackageReference Include="LanguageExt.Core" Version="4.4.8" />
|
||||
<PackageReference Include="LanguageExt.Core" Version="5.0.0-beta-01" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.6.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.7.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.6.2" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.6.15" />
|
||||
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
|
||||
<PackageReference Include="Nito.Comparers" Version="6.2.2" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
|
||||
<PackageReference Include="Polly" Version="8.4.0" />
|
||||
<PackageReference Include="Polly" Version="8.4.1" />
|
||||
<PackageReference Include="System.Interactive.Async" Version="6.0.1" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="Yaml2JsonNode" Version="2.1.0" />
|
||||
<PackageReference Include="YamlDotNet.System.Text.Json" Version="1.4.0" />
|
||||
<PackageReference Include="Yaml2JsonNode" Version="2.1.1" />
|
||||
<PackageReference Include="YamlDotNet.System.Text.Json" Version="1.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -4,45 +4,41 @@ using LanguageExt;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractApis(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractApis(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ApiName Name, ApiDto Dto, Option<(ApiSpecification Specification, BinaryData Contents)> SpecificationOption)> ListApis(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractApiName(ApiName name);
|
||||
public delegate bool ShouldExtractApiDto(ApiDto dto);
|
||||
public delegate ValueTask WriteApiArtifacts(ApiName name, ApiDto dto, Option<(ApiSpecification Specification, BinaryData Contents)> specificationOption, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiInformationFile(ApiName name, ApiDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiSpecificationFile(ApiName name, ApiSpecification specification, BinaryData contents, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate IAsyncEnumerable<(ApiName Name, ApiDto Dto, Option<(ApiSpecification Specification, BinaryData Contents)> SpecificationOption)> ListApis(CancellationToken cancellationToken);
|
||||
|
||||
internal delegate bool ShouldExtractApiName(ApiName name);
|
||||
|
||||
internal delegate bool ShouldExtractApiDto(ApiDto dto);
|
||||
|
||||
internal delegate ValueTask WriteApiArtifacts(ApiName name, ApiDto dto, Option<(ApiSpecification Specification, BinaryData Contents)> specificationOption, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiInformationFile(ApiName name, ApiDto dto, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiSpecificationFile(ApiName name, ApiSpecification specification, BinaryData contents, CancellationToken cancellationToken);
|
||||
|
||||
internal static class ApiServices
|
||||
internal static class ApiModule
|
||||
{
|
||||
public static void ConfigureExtractApis(IServiceCollection services)
|
||||
public static void ConfigureExtractApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListApis(services);
|
||||
ConfigureShouldExtractApiName(services);
|
||||
ConfigureShouldExtractApiDto(services);
|
||||
ConfigureWriteApiArtifacts(services);
|
||||
ApiPolicyServices.ConfigureExtractApiPolicies(services);
|
||||
ApiTagServices.ConfigureExtractApiTags(services);
|
||||
ApiOperationServices.ConfigureExtractApiOperations(services);
|
||||
ConfigureListApis(builder);
|
||||
ConfigureShouldExtractApiName(builder);
|
||||
ConfigureShouldExtractApiDto(builder);
|
||||
ConfigureWriteApiArtifacts(builder);
|
||||
ApiPolicyModule.ConfigureExtractApiPolicies(builder);
|
||||
ApiTagModule.ConfigureExtractApiTags(builder);
|
||||
ApiOperationModule.ConfigureExtractApiOperations(builder);
|
||||
|
||||
services.TryAddSingleton(ExtractApis);
|
||||
builder.Services.TryAddSingleton(GetExtractApis);
|
||||
}
|
||||
|
||||
private static ExtractApis ExtractApis(IServiceProvider provider)
|
||||
private static ExtractApis GetExtractApis(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListApis>();
|
||||
var shouldExtractName = provider.GetRequiredService<ShouldExtractApiName>();
|
||||
|
@ -51,8 +47,15 @@ internal static class ApiServices
|
|||
var extractApiPolicies = provider.GetRequiredService<ExtractApiPolicies>();
|
||||
var extractApiTags = provider.GetRequiredService<ExtractApiTags>();
|
||||
var extractApiOperations = provider.GetRequiredService<ExtractApiOperations>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractApis));
|
||||
|
||||
logger.LogInformation("Extracting APIs...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(api => shouldExtractName(api.Name))
|
||||
.Where(api => shouldExtractDto(api.Dto))
|
||||
|
@ -62,6 +65,7 @@ internal static class ApiServices
|
|||
.IterParallel(async group => await group.Iter(async api => await extractApi(api.Name, api.Dto, api.SpecificationOption, cancellationToken),
|
||||
cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
|
||||
async ValueTask extractApi(ApiName name, ApiDto dto, Option<(ApiSpecification Specification, BinaryData Contents)> specificationOption, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -72,21 +76,20 @@ internal static class ApiServices
|
|||
}
|
||||
}
|
||||
|
||||
private static void ConfigureListApis(IServiceCollection services)
|
||||
private static void ConfigureListApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceUri(services);
|
||||
CommonServices.ConfigureHttpPipeline(services);
|
||||
ApiSpecificationModule.ConfigureDefaultApiSpecification(builder);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton(ListApis);
|
||||
builder.Services.TryAddSingleton(GetListApis);
|
||||
}
|
||||
|
||||
private static ListApis ListApis(IServiceProvider provider)
|
||||
private static ListApis GetListApis(IServiceProvider provider)
|
||||
{
|
||||
var defaultApiSpecification = provider.GetRequiredService<DefaultApiSpecification>();
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var defaultApiSpecification = getDefaultApiSpecification(configuration);
|
||||
|
||||
return cancellationToken =>
|
||||
ApisUri.From(serviceUri)
|
||||
|
@ -98,52 +101,6 @@ internal static class ApiServices
|
|||
return (name, dto, specificationContentsOption);
|
||||
});
|
||||
|
||||
static ApiSpecification getDefaultApiSpecification(IConfiguration configuration)
|
||||
{
|
||||
var formatOption = configuration.TryGetValue("API_SPECIFICATION_FORMAT")
|
||||
| configuration.TryGetValue("apiSpecificationFormat");
|
||||
|
||||
return formatOption.Map(format => format switch
|
||||
{
|
||||
var value when "Wadl".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.Wadl() as ApiSpecification,
|
||||
var value when "JSON".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Json(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
},
|
||||
var value when "YAML".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
},
|
||||
var value when "OpenApiV2Json".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Json(),
|
||||
Version = new OpenApiVersion.V2()
|
||||
},
|
||||
var value when "OpenApiV2Yaml".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V2()
|
||||
},
|
||||
var value when "OpenApiV3Json".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Json(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
},
|
||||
var value when "OpenApiV3Yaml".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
},
|
||||
var value => throw new NotSupportedException($"API specification format '{value}' defined in configuration is not supported.")
|
||||
}).IfNone(() => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
});
|
||||
}
|
||||
|
||||
async ValueTask<Option<(ApiSpecification, BinaryData)>> tryGetSpecificationContents(ApiName name, ApiDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var specificationOption = tryGetSpecification(dto);
|
||||
|
@ -163,20 +120,20 @@ internal static class ApiServices
|
|||
{
|
||||
"graphql" => new ApiSpecification.GraphQl(),
|
||||
"soap" => new ApiSpecification.Wsdl(),
|
||||
"http" => defaultApiSpecification,
|
||||
null => defaultApiSpecification,
|
||||
"http" => defaultApiSpecification.Value,
|
||||
null => defaultApiSpecification.Value,
|
||||
_ => Option<ApiSpecification>.None
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractApiName(IServiceCollection services)
|
||||
public static void ConfigureShouldExtractApiName(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureShouldExtractFactory(services);
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
services.TryAddSingleton(ShouldExtractApiName);
|
||||
builder.Services.TryAddSingleton(GetShouldExtractApiName);
|
||||
}
|
||||
|
||||
private static ShouldExtractApiName ShouldExtractApiName(IServiceProvider provider)
|
||||
private static ShouldExtractApiName GetShouldExtractApiName(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
|
@ -185,31 +142,31 @@ internal static class ApiServices
|
|||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractApiDto(IServiceCollection services)
|
||||
public static void ConfigureShouldExtractApiDto(IHostApplicationBuilder builder)
|
||||
{
|
||||
services.TryAddSingleton(ShouldExtractApiDto);
|
||||
builder.Services.TryAddSingleton(GetShouldExtractApiDto);
|
||||
}
|
||||
|
||||
private static ShouldExtractApiDto ShouldExtractApiDto(IServiceProvider provider)
|
||||
private static ShouldExtractApiDto GetShouldExtractApiDto(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractVersionSet = provider.GetRequiredService<ShouldExtractVersionSet>();
|
||||
|
||||
return dto =>
|
||||
// Don't extract if its version set should not be extracted
|
||||
ApiModule.TryGetVersionSetName(dto)
|
||||
.Map(shouldExtractVersionSet.Invoke)
|
||||
.IfNone(true);
|
||||
common.ApiModule.TryGetVersionSetName(dto)
|
||||
.Map(shouldExtractVersionSet.Invoke)
|
||||
.IfNone(true);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiArtifacts(IServiceCollection services)
|
||||
private static void ConfigureWriteApiArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteApiInformationFile(services);
|
||||
ConfigureWriteApiSpecificationFile(services);
|
||||
ConfigureWriteApiInformationFile(builder);
|
||||
ConfigureWriteApiSpecificationFile(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiArtifacts);
|
||||
builder.Services.TryAddSingleton(GetWriteApiArtifacts);
|
||||
}
|
||||
|
||||
private static WriteApiArtifacts WriteApiArtifacts(IServiceProvider provider)
|
||||
private static WriteApiArtifacts GetWriteApiArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteApiInformationFile>();
|
||||
var writeSpecificationFile = provider.GetRequiredService<WriteApiSpecificationFile>();
|
||||
|
@ -226,19 +183,17 @@ internal static class ApiServices
|
|||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiInformationFile(IServiceCollection services)
|
||||
private static void ConfigureWriteApiInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceDirectory(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiInformationFile);
|
||||
builder.Services.TryAddSingleton(GetWriteApiInformationFile);
|
||||
}
|
||||
|
||||
private static WriteApiInformationFile WriteApiInformationFile(IServiceProvider provider)
|
||||
private static WriteApiInformationFile GetWriteApiInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = Common.GetLogger(loggerFactory);
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
|
@ -249,19 +204,17 @@ internal static class ApiServices
|
|||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiSpecificationFile(IServiceCollection services)
|
||||
private static void ConfigureWriteApiSpecificationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceDirectory(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiSpecificationFile);
|
||||
builder.Services.TryAddSingleton(GetWriteApiSpecificationFile);
|
||||
}
|
||||
|
||||
private static WriteApiSpecificationFile WriteApiSpecificationFile(IServiceProvider provider)
|
||||
private static WriteApiSpecificationFile GetWriteApiSpecificationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = Common.GetLogger(loggerFactory);
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, specification, contents, cancellationToken) =>
|
||||
{
|
||||
|
@ -271,10 +224,4 @@ internal static class ApiServices
|
|||
await specificationFile.WriteSpecification(contents, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ApiExtractor");
|
||||
}
|
|
@ -2,51 +2,57 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractApiOperations(ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractApiOperations(ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<ApiOperationName> ListApiOperations(ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate IAsyncEnumerable<ApiOperationName> ListApiOperations(ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class ApiOperationServices
|
||||
internal static class ApiOperationModule
|
||||
{
|
||||
public static void ConfigureExtractApiOperations(IServiceCollection services)
|
||||
public static void ConfigureExtractApiOperations(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListApiOperations(services);
|
||||
ApiOperationPolicyServices.ConfigureExtractApiOperationPolicies(services);
|
||||
ConfigureListApiOperations(builder);
|
||||
ApiOperationPolicyModule.ConfigureExtractApiOperationPolicies(builder);
|
||||
|
||||
services.TryAddSingleton(ExtractApiOperations);
|
||||
builder.Services.TryAddSingleton(GetExtractApiOperations);
|
||||
}
|
||||
|
||||
private static ExtractApiOperations ExtractApiOperations(IServiceProvider provider)
|
||||
private static ExtractApiOperations GetExtractApiOperations(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListApiOperations>();
|
||||
var extractPolicies = provider.GetRequiredService<ExtractApiOperationPolicies>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = Common.GetLogger(loggerFactory);
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (apiName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractApiOperations));
|
||||
|
||||
logger.LogInformation("Extracting API operations for {ApiName}...", apiName);
|
||||
|
||||
await list(apiName, cancellationToken)
|
||||
.IterParallel(async name => await extractPolicies(name, apiName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListApiOperations(IServiceCollection services)
|
||||
private static void ConfigureListApiOperations(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceUri(services);
|
||||
CommonServices.ConfigureHttpPipeline(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton(ListApiOperations);
|
||||
builder.Services.TryAddSingleton(GetListApiOperations);
|
||||
}
|
||||
|
||||
private static ListApiOperations ListApiOperations(IServiceProvider provider)
|
||||
private static ListApiOperations GetListApiOperations(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
@ -55,10 +61,4 @@ internal static class ApiOperationServices
|
|||
ApiOperationsUri.From(apiName, serviceUri)
|
||||
.ListNames(pipeline, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ApiOperationExtractor");
|
||||
}
|
|
@ -2,52 +2,59 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractApiOperationPolicies(ApiOperationName apiOperationName, ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractApiOperationPolicies(ApiOperationName apiOperationName, ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ApiOperationPolicyName Name, ApiOperationPolicyDto Dto)> ListApiOperationPolicies(ApiOperationName apiOperationName, ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiOperationPolicyArtifacts(ApiOperationPolicyName name, ApiOperationPolicyDto dto, ApiOperationName apiOperationName, ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiOperationPolicyFile(ApiOperationPolicyName name, ApiOperationPolicyDto dto, ApiOperationName apiOperationName, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate IAsyncEnumerable<(ApiOperationPolicyName Name, ApiOperationPolicyDto Dto)> ListApiOperationPolicies(ApiOperationName apiOperationName, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiOperationPolicyArtifacts(ApiOperationPolicyName name, ApiOperationPolicyDto dto, ApiOperationName apiOperationName, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiOperationPolicyFile(ApiOperationPolicyName name, ApiOperationPolicyDto dto, ApiOperationName apiOperationName, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class ApiOperationPolicyServices
|
||||
internal static class ApiOperationPolicyModule
|
||||
{
|
||||
public static void ConfigureExtractApiOperationPolicies(IServiceCollection services)
|
||||
public static void ConfigureExtractApiOperationPolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListApiOperationPolicies(services);
|
||||
ConfigureWriteApiOperationPolicyArtifacts(services);
|
||||
ConfigureListApiOperationPolicies(builder);
|
||||
ConfigureWriteApiOperationPolicyArtifacts(builder);
|
||||
|
||||
services.TryAddSingleton(ExtractApiOperationPolicies);
|
||||
builder.Services.TryAddSingleton(GetExtractApiOperationPolicies);
|
||||
}
|
||||
|
||||
private static ExtractApiOperationPolicies ExtractApiOperationPolicies(IServiceProvider provider)
|
||||
private static ExtractApiOperationPolicies GetExtractApiOperationPolicies(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListApiOperationPolicies>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteApiOperationPolicyArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (operationName, apiName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractApiOperationPolicies));
|
||||
|
||||
logger.LogInformation("Extracting policies for operation {ApiOperationName} in API {ApiName}...", operationName, apiName);
|
||||
|
||||
await list(operationName, apiName, cancellationToken)
|
||||
.IterParallel(async policy => await writeArtifacts(policy.Name, policy.Dto, operationName, apiName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListApiOperationPolicies(IServiceCollection services)
|
||||
private static void ConfigureListApiOperationPolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceUri(services);
|
||||
CommonServices.ConfigureHttpPipeline(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton(ListApiOperationPolicies);
|
||||
builder.Services.TryAddSingleton(GetListApiOperationPolicies);
|
||||
}
|
||||
|
||||
private static ListApiOperationPolicies ListApiOperationPolicies(IServiceProvider provider)
|
||||
private static ListApiOperationPolicies GetListApiOperationPolicies(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
@ -57,14 +64,14 @@ internal static class ApiOperationPolicyServices
|
|||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiOperationPolicyArtifacts(IServiceCollection services)
|
||||
private static void ConfigureWriteApiOperationPolicyArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteApiOperationPolicyFile(services);
|
||||
ConfigureWriteApiOperationPolicyFile(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiOperationPolicyArtifacts);
|
||||
builder.Services.TryAddSingleton(GetWriteApiOperationPolicyArtifacts);
|
||||
}
|
||||
|
||||
private static WriteApiOperationPolicyArtifacts WriteApiOperationPolicyArtifacts(IServiceProvider provider)
|
||||
private static WriteApiOperationPolicyArtifacts GetWriteApiOperationPolicyArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writePolicyFile = provider.GetRequiredService<WriteApiOperationPolicyFile>();
|
||||
|
||||
|
@ -72,19 +79,17 @@ internal static class ApiOperationPolicyServices
|
|||
await writePolicyFile(name, dto, operationName, apiName, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiOperationPolicyFile(IServiceCollection services)
|
||||
private static void ConfigureWriteApiOperationPolicyFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceDirectory(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiOperationPolicyFile);
|
||||
builder.Services.TryAddSingleton(GetWriteApiOperationPolicyFile);
|
||||
}
|
||||
|
||||
private static WriteApiOperationPolicyFile WriteApiOperationPolicyFile(IServiceProvider provider)
|
||||
private static WriteApiOperationPolicyFile GetWriteApiOperationPolicyFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = Common.GetLogger(loggerFactory);
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, operationName, apiName, cancellationToken) =>
|
||||
{
|
||||
|
@ -95,10 +100,4 @@ internal static class ApiOperationPolicyServices
|
|||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ApiOperationPolicyExtractor");
|
||||
}
|
|
@ -2,52 +2,59 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractApiPolicies(ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractApiPolicies(ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ApiPolicyName Name, ApiPolicyDto Dto)> ListApiPolicies(ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiPolicyArtifacts(ApiPolicyName name, ApiPolicyDto dto, ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiPolicyFile(ApiPolicyName name, ApiPolicyDto dto, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate IAsyncEnumerable<(ApiPolicyName Name, ApiPolicyDto Dto)> ListApiPolicies(ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiPolicyArtifacts(ApiPolicyName name, ApiPolicyDto dto, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiPolicyFile(ApiPolicyName name, ApiPolicyDto dto, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class ApiPolicyServices
|
||||
internal static class ApiPolicyModule
|
||||
{
|
||||
public static void ConfigureExtractApiPolicies(IServiceCollection services)
|
||||
public static void ConfigureExtractApiPolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListApiPolicies(services);
|
||||
ConfigureWriteApiPolicyArtifacts(services);
|
||||
ConfigureListApiPolicies(builder);
|
||||
ConfigureWriteApiPolicyArtifacts(builder);
|
||||
|
||||
services.TryAddSingleton(ExtractApiPolicies);
|
||||
builder.Services.TryAddSingleton(GetExtractApiPolicies);
|
||||
}
|
||||
|
||||
private static ExtractApiPolicies ExtractApiPolicies(IServiceProvider provider)
|
||||
private static ExtractApiPolicies GetExtractApiPolicies(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListApiPolicies>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteApiPolicyArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (apiName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractApiPolicies));
|
||||
|
||||
logger.LogInformation("Extracting policies for API {ApiName}...", apiName);
|
||||
|
||||
await list(apiName, cancellationToken)
|
||||
.IterParallel(async policy => await writeArtifacts(policy.Name, policy.Dto, apiName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListApiPolicies(IServiceCollection services)
|
||||
private static void ConfigureListApiPolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceUri(services);
|
||||
CommonServices.ConfigureHttpPipeline(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton(ListApiPolicies);
|
||||
builder.Services.TryAddSingleton(GetListApiPolicies);
|
||||
}
|
||||
|
||||
private static ListApiPolicies ListApiPolicies(IServiceProvider provider)
|
||||
private static ListApiPolicies GetListApiPolicies(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
@ -57,14 +64,14 @@ internal static class ApiPolicyServices
|
|||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiPolicyArtifacts(IServiceCollection services)
|
||||
private static void ConfigureWriteApiPolicyArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteApiPolicyFile(services);
|
||||
ConfigureWriteApiPolicyFile(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiPolicyArtifacts);
|
||||
builder.Services.TryAddSingleton(GetWriteApiPolicyArtifacts);
|
||||
}
|
||||
|
||||
private static WriteApiPolicyArtifacts WriteApiPolicyArtifacts(IServiceProvider provider)
|
||||
private static WriteApiPolicyArtifacts GetWriteApiPolicyArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writePolicyFile = provider.GetRequiredService<WriteApiPolicyFile>();
|
||||
|
||||
|
@ -72,19 +79,17 @@ internal static class ApiPolicyServices
|
|||
await writePolicyFile(name, dto, apiName, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiPolicyFile(IServiceCollection services)
|
||||
private static void ConfigureWriteApiPolicyFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceDirectory(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiPolicyFile);
|
||||
builder.Services.TryAddSingleton(GetWriteApiPolicyFile);
|
||||
}
|
||||
|
||||
private static WriteApiPolicyFile WriteApiPolicyFile(IServiceProvider provider)
|
||||
private static WriteApiPolicyFile GetWriteApiPolicyFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = Common.GetLogger(loggerFactory);
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, apiName, cancellationToken) =>
|
||||
{
|
||||
|
@ -95,10 +100,4 @@ internal static class ApiPolicyServices
|
|||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ApiPolicyExtractor");
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
using common;
|
||||
using LanguageExt;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal sealed record DefaultApiSpecification(ApiSpecification Value);
|
||||
|
||||
internal static class ApiSpecificationModule
|
||||
{
|
||||
public static void ConfigureDefaultApiSpecification(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetDefaultApiSpecification);
|
||||
}
|
||||
|
||||
private static DefaultApiSpecification GetDefaultApiSpecification(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var formatOption = configuration.TryGetValue("API_SPECIFICATION_FORMAT")
|
||||
| configuration.TryGetValue("apiSpecificationFormat");
|
||||
|
||||
var specification = formatOption.Map(format => format switch
|
||||
{
|
||||
var value when "Wadl".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.Wadl() as ApiSpecification,
|
||||
var value when "JSON".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Json(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
},
|
||||
var value when "YAML".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
},
|
||||
var value when "OpenApiV2Json".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Json(),
|
||||
Version = new OpenApiVersion.V2()
|
||||
},
|
||||
var value when "OpenApiV2Yaml".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V2()
|
||||
},
|
||||
var value when "OpenApiV3Json".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Json(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
},
|
||||
var value when "OpenApiV3Yaml".Equals(value, StringComparison.OrdinalIgnoreCase) => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
},
|
||||
var value => throw new NotSupportedException($"API specification format '{value}' defined in configuration is not supported.")
|
||||
}).IfNone(() => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
});
|
||||
|
||||
return new DefaultApiSpecification(specification);
|
||||
}
|
||||
}
|
|
@ -2,56 +2,63 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractApiTags(ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractApiTags(ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(TagName Name, ApiTagDto Dto)> ListApiTags(ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiTagArtifacts(TagName name, ApiTagDto dto, ApiName apiName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiTagInformationFile(TagName name, ApiTagDto dto, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate IAsyncEnumerable<(TagName Name, ApiTagDto Dto)> ListApiTags(ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiTagArtifacts(TagName name, ApiTagDto dto, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiTagInformationFile(TagName name, ApiTagDto dto, ApiName apiName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class ApiTagServices
|
||||
internal static class ApiTagModule
|
||||
{
|
||||
public static void ConfigureExtractApiTags(IServiceCollection services)
|
||||
public static void ConfigureExtractApiTags(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListApiTags(services);
|
||||
TagServices.ConfigureShouldExtractTag(services);
|
||||
ConfigureWriteApiTagArtifacts(services);
|
||||
ConfigureListApiTags(builder);
|
||||
TagModule.ConfigureShouldExtractTag(builder);
|
||||
ConfigureWriteApiTagArtifacts(builder);
|
||||
|
||||
services.TryAddSingleton(ExtractApiTags);
|
||||
builder.Services.TryAddSingleton(GetExtractApiTags);
|
||||
}
|
||||
|
||||
private static ExtractApiTags ExtractApiTags(IServiceProvider provider)
|
||||
private static ExtractApiTags GetExtractApiTags(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListApiTags>();
|
||||
var shouldExtractTag = provider.GetRequiredService<ShouldExtractTag>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteApiTagArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (apiName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractApiTags));
|
||||
|
||||
logger.LogInformation("Extracting tags for API {ApiName}...", apiName);
|
||||
|
||||
await list(apiName, cancellationToken)
|
||||
.Where(tag => shouldExtractTag(tag.Name))
|
||||
.IterParallel(async tag => await writeArtifacts(tag.Name, tag.Dto, apiName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListApiTags(IServiceCollection services)
|
||||
private static void ConfigureListApiTags(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceUri(services);
|
||||
CommonServices.ConfigureHttpPipeline(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton(ListApiTags);
|
||||
builder.Services.TryAddSingleton(GetListApiTags);
|
||||
}
|
||||
|
||||
private static ListApiTags ListApiTags(IServiceProvider provider)
|
||||
private static ListApiTags GetListApiTags(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
@ -61,14 +68,14 @@ internal static class ApiTagServices
|
|||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiTagArtifacts(IServiceCollection services)
|
||||
private static void ConfigureWriteApiTagArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteApiTagInformationFile(services);
|
||||
ConfigureWriteApiTagInformationFile(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiTagArtifacts);
|
||||
builder.Services.TryAddSingleton(GetWriteApiTagArtifacts);
|
||||
}
|
||||
|
||||
private static WriteApiTagArtifacts WriteApiTagArtifacts(IServiceProvider provider)
|
||||
private static WriteApiTagArtifacts GetWriteApiTagArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteApiTagInformationFile>();
|
||||
|
||||
|
@ -76,19 +83,17 @@ internal static class ApiTagServices
|
|||
await writeInformationFile(name, dto, apiName, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteApiTagInformationFile(IServiceCollection services)
|
||||
private static void ConfigureWriteApiTagInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceDirectory(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton(WriteApiTagInformationFile);
|
||||
builder.Services.TryAddSingleton(GetWriteApiTagInformationFile);
|
||||
}
|
||||
|
||||
private static WriteApiTagInformationFile WriteApiTagInformationFile(IServiceProvider provider)
|
||||
private static WriteApiTagInformationFile GetWriteApiTagInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = Common.GetLogger(loggerFactory);
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, apiName, cancellationToken) =>
|
||||
{
|
||||
|
@ -98,10 +103,4 @@ internal static class ApiTagServices
|
|||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ApiTagExtractor");
|
||||
}
|
|
@ -1,36 +1,38 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.FeatureManagement;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask RunExtractor(CancellationToken cancellationToken);
|
||||
|
||||
internal static class AppServices
|
||||
internal static class AppModule
|
||||
{
|
||||
public static void ConfigureRunExtractor(IServiceCollection services)
|
||||
public static void ConfigureRunApplication(IHostApplicationBuilder builder)
|
||||
{
|
||||
NamedValueServices.ConfigureExtractNamedValues(services);
|
||||
TagServices.ConfigureExtractTags(services);
|
||||
GatewayServices.ConfigureExtractGateways(services);
|
||||
VersionSetServices.ConfigureExtractVersionSets(services);
|
||||
BackendServices.ConfigureExtractBackends(services);
|
||||
LoggerServices.ConfigureExtractLoggers(services);
|
||||
DiagnosticServices.ConfigureExtractDiagnostics(services);
|
||||
PolicyFragmentServices.ConfigureExtractPolicyFragments(services);
|
||||
ServicePolicyServices.ConfigureExtractServicePolicies(services);
|
||||
ProductServices.ConfigureExtractProducts(services);
|
||||
GroupServices.ConfigureExtractGroups(services);
|
||||
SubscriptionServices.ConfigureExtractSubscriptions(services);
|
||||
ApiServices.ConfigureExtractApis(services);
|
||||
NamedValueModule.ConfigureExtractNamedValues(builder);
|
||||
TagModule.ConfigureExtractTags(builder);
|
||||
GatewayModule.ConfigureExtractGateways(builder);
|
||||
VersionSetModule.ConfigureExtractVersionSets(builder);
|
||||
BackendModule.ConfigureExtractBackends(builder);
|
||||
LoggerModule.ConfigureExtractLoggers(builder);
|
||||
DiagnosticModule.ConfigureExtractDiagnostics(builder);
|
||||
PolicyFragmentModule.ConfigureExtractPolicyFragments(builder);
|
||||
ServicePolicyModule.ConfigureExtractServicePolicies(builder);
|
||||
ProductModule.ConfigureExtractProducts(builder);
|
||||
GroupModule.ConfigureExtractGroups(builder);
|
||||
SubscriptionModule.ConfigureExtractSubscriptions(builder);
|
||||
ApiModule.ConfigureExtractApis(builder);
|
||||
WorkspaceModule.ConfigureExtractWorkspaces(builder);
|
||||
builder.Services.AddFeatureManagement();
|
||||
|
||||
services.TryAddSingleton(RunExtractor);
|
||||
builder.Services.TryAddSingleton(GetRunApplication);
|
||||
}
|
||||
|
||||
private static RunExtractor RunExtractor(IServiceProvider provider)
|
||||
private static RunApplication GetRunApplication(IServiceProvider provider)
|
||||
{
|
||||
var extractNamedValues = provider.GetRequiredService<ExtractNamedValues>();
|
||||
var extractTags = provider.GetRequiredService<ExtractTags>();
|
||||
|
@ -45,12 +47,15 @@ internal static class AppServices
|
|||
var extractGroups = provider.GetRequiredService<ExtractGroups>();
|
||||
var extractSubscriptions = provider.GetRequiredService<ExtractSubscriptions>();
|
||||
var extractApis = provider.GetRequiredService<ExtractApis>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = loggerFactory.CreateLogger("Extractor");
|
||||
var extractWorkspaces = provider.GetRequiredService<ExtractWorkspaces>();
|
||||
var featureManager = provider.GetRequiredService<IFeatureManager>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var activity = activitySource.StartActivity(nameof(RunApplication));
|
||||
|
||||
logger.LogInformation("Running extractor...");
|
||||
|
||||
await extractNamedValues(cancellationToken);
|
||||
|
@ -67,6 +72,11 @@ internal static class AppServices
|
|||
await extractSubscriptions(cancellationToken);
|
||||
await extractApis(cancellationToken);
|
||||
|
||||
if (await featureManager.IsEnabledAsync("Workspaces"))
|
||||
{
|
||||
await extractWorkspaces(cancellationToken);
|
||||
}
|
||||
|
||||
logger.LogInformation("Extractor completed.");
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,77 +1,84 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractBackends(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractBackends(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(BackendName Name, BackendDto Dto)> ListBackends(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractBackend(BackendName name);
|
||||
public delegate ValueTask WriteBackendArtifacts(BackendName name, BackendDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteBackendInformationFile(BackendName name, BackendDto dto, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate IAsyncEnumerable<(BackendName Name, BackendDto Dto)> ListBackends(CancellationToken cancellationToken);
|
||||
|
||||
internal delegate bool ShouldExtractBackend(BackendName name);
|
||||
|
||||
internal delegate ValueTask WriteBackendArtifacts(BackendName name, BackendDto dto, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteBackendInformationFile(BackendName name, BackendDto dto, CancellationToken cancellationToken);
|
||||
|
||||
internal static class BackendServices
|
||||
internal static class BackendModule
|
||||
{
|
||||
public static void ConfigureExtractBackends(IServiceCollection services)
|
||||
public static void ConfigureExtractBackends(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListBackends(services);
|
||||
ConfigureShouldExtractBackend(services);
|
||||
ConfigureWriteBackendArtifacts(services);
|
||||
ConfigureListBackends(builder);
|
||||
ConfigureShouldExtractBackend(builder);
|
||||
ConfigureWriteBackendArtifacts(builder);
|
||||
|
||||
services.TryAddSingleton(ExtractBackends);
|
||||
builder.Services.TryAddSingleton(GetExtractBackends);
|
||||
}
|
||||
|
||||
private static ExtractBackends ExtractBackends(IServiceProvider provider)
|
||||
private static ExtractBackends GetExtractBackends(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListBackends>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractBackend>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteBackendArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractBackends));
|
||||
|
||||
logger.LogInformation("Extracting backends...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(backend => shouldExtract(backend.Name))
|
||||
.IterParallel(async backend => await writeArtifacts(backend.Name, backend.Dto, cancellationToken),
|
||||
.Where(resource => shouldExtract(resource.Name))
|
||||
.IterParallel(async resource => await writeArtifacts(resource.Name, resource.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListBackends(IServiceCollection services)
|
||||
private static void ConfigureListBackends(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceUri(services);
|
||||
CommonServices.ConfigureHttpPipeline(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton(ListBackends);
|
||||
builder.Services.TryAddSingleton(GetListBackends);
|
||||
}
|
||||
|
||||
private static ListBackends ListBackends(IServiceProvider provider)
|
||||
private static ListBackends GetListBackends(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
BackendsUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
{
|
||||
var backendsUri = BackendsUri.From(serviceUri);
|
||||
return backendsUri.List(pipeline, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractBackend(IServiceCollection services)
|
||||
private static void ConfigureShouldExtractBackend(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureShouldExtractFactory(services);
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
services.TryAddSingleton(ShouldExtractBackend);
|
||||
builder.Services.TryAddSingleton(GetShouldExtractBackend);
|
||||
}
|
||||
|
||||
private static ShouldExtractBackend ShouldExtractBackend(IServiceProvider provider)
|
||||
private static ShouldExtractBackend GetShouldExtractBackend(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
|
@ -80,14 +87,14 @@ internal static class BackendServices
|
|||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteBackendArtifacts(IServiceCollection services)
|
||||
private static void ConfigureWriteBackendArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteBackendInformationFile(services);
|
||||
ConfigureWriteBackendInformationFile(builder);
|
||||
|
||||
services.TryAddSingleton(WriteBackendArtifacts);
|
||||
builder.Services.TryAddSingleton(GetWriteBackendArtifacts);
|
||||
}
|
||||
|
||||
private static WriteBackendArtifacts WriteBackendArtifacts(IServiceProvider provider)
|
||||
private static WriteBackendArtifacts GetWriteBackendArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteBackendInformationFile>();
|
||||
|
||||
|
@ -95,19 +102,17 @@ internal static class BackendServices
|
|||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteBackendInformationFile(IServiceCollection services)
|
||||
private static void ConfigureWriteBackendInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceDirectory(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton(WriteBackendInformationFile);
|
||||
builder.Services.TryAddSingleton(GetWriteBackendInformationFile);
|
||||
}
|
||||
|
||||
private static WriteBackendInformationFile WriteBackendInformationFile(IServiceProvider provider)
|
||||
private static WriteBackendInformationFile GetWriteBackendInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = Common.GetLogger(loggerFactory);
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
|
@ -117,10 +122,4 @@ internal static class BackendServices
|
|||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("BackendExtractor");
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
using Azure.Core;
|
||||
using Azure.Core.Pipeline;
|
||||
using Azure.Identity;
|
||||
using Azure.ResourceManager;
|
||||
using common;
|
||||
using Flurl;
|
||||
using LanguageExt;
|
||||
using LanguageExt.UnsafeValueAccess;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal static class CommonServices
|
||||
{
|
||||
public static void Configure(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton(GetActivitySource);
|
||||
services.AddSingleton(GetAzureEnvironment);
|
||||
services.AddSingleton(GetTokenCredential);
|
||||
services.AddSingleton(GetHttpPipeline);
|
||||
services.AddSingleton(GetManagementServiceName);
|
||||
services.AddSingleton(GetManagementServiceUri);
|
||||
services.AddSingleton(GetManagementServiceDirectory);
|
||||
services.AddSingleton(GetConfigurationJson);
|
||||
services.AddSingleton<ShouldExtractFactory>();
|
||||
OpenTelemetryServices.Configure(services);
|
||||
}
|
||||
|
||||
private static ActivitySource GetActivitySource(IServiceProvider provider) =>
|
||||
new("ApiOps.Extractor");
|
||||
|
||||
private static AzureEnvironment GetAzureEnvironment(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
return configuration.TryGetValue("AZURE_CLOUD_ENVIRONMENT").ValueUnsafe() switch
|
||||
{
|
||||
null => AzureEnvironment.Public,
|
||||
"AzureGlobalCloud" or nameof(ArmEnvironment.AzurePublicCloud) => AzureEnvironment.Public,
|
||||
"AzureChinaCloud" or nameof(ArmEnvironment.AzureChina) => AzureEnvironment.China,
|
||||
"AzureUSGovernment" or nameof(ArmEnvironment.AzureGovernment) => AzureEnvironment.USGovernment,
|
||||
"AzureGermanCloud" or nameof(ArmEnvironment.AzureGermany) => AzureEnvironment.Germany,
|
||||
_ => throw new InvalidOperationException($"AZURE_CLOUD_ENVIRONMENT is invalid. Valid values are {nameof(ArmEnvironment.AzurePublicCloud)}, {nameof(ArmEnvironment.AzureChina)}, {nameof(ArmEnvironment.AzureGovernment)}, {nameof(ArmEnvironment.AzureGermany)}")
|
||||
};
|
||||
}
|
||||
|
||||
private static TokenCredential GetTokenCredential(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
var azureAuthorityHost = provider.GetRequiredService<AzureEnvironment>().AuthorityHost;
|
||||
|
||||
return configuration.TryGetValue("AZURE_BEARER_TOKEN")
|
||||
.Map(GetCredentialFromToken)
|
||||
.IfNone(() => GetDefaultAzureCredential(azureAuthorityHost));
|
||||
}
|
||||
|
||||
private static TokenCredential GetCredentialFromToken(string token)
|
||||
{
|
||||
var jsonWebToken = new JsonWebToken(token);
|
||||
var expirationDate = new DateTimeOffset(jsonWebToken.ValidTo);
|
||||
var accessToken = new AccessToken(token, expirationDate);
|
||||
|
||||
return DelegatedTokenCredential.Create((context, cancellationToken) => accessToken);
|
||||
}
|
||||
|
||||
private static DefaultAzureCredential GetDefaultAzureCredential(Uri azureAuthorityHost) =>
|
||||
new(new DefaultAzureCredentialOptions
|
||||
{
|
||||
AuthorityHost = azureAuthorityHost
|
||||
});
|
||||
|
||||
public static void ConfigureHttpPipeline(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton(GetHttpPipeline);
|
||||
}
|
||||
|
||||
private static HttpPipeline GetHttpPipeline(IServiceProvider provider)
|
||||
{
|
||||
var clientOptions = ClientOptions.Default;
|
||||
clientOptions.RetryPolicy = new CommonRetryPolicy();
|
||||
|
||||
var tokenCredential = provider.GetRequiredService<TokenCredential>();
|
||||
var azureEnvironment = provider.GetRequiredService<AzureEnvironment>();
|
||||
var bearerAuthenticationPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, azureEnvironment.DefaultScope);
|
||||
|
||||
var logger = provider.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(HttpPipeline));
|
||||
var loggingPolicy = new ILoggerHttpPipelinePolicy(logger);
|
||||
|
||||
var version = Assembly.GetExecutingAssembly()?.GetName().Version ?? new Version("-1");
|
||||
var telemetryPolicy = new TelemetryPolicy(version);
|
||||
|
||||
return HttpPipelineBuilder.Build(clientOptions, bearerAuthenticationPolicy, loggingPolicy, telemetryPolicy);
|
||||
}
|
||||
|
||||
private static ManagementServiceName GetManagementServiceName(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var name = configuration.TryGetValue("API_MANAGEMENT_SERVICE_NAME")
|
||||
.IfNone(() => configuration.GetValue("apimServiceName"));
|
||||
|
||||
return ManagementServiceName.From(name);
|
||||
}
|
||||
|
||||
public static void ConfigureManagementServiceUri(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton(GetManagementServiceUri);
|
||||
}
|
||||
|
||||
private static ManagementServiceUri GetManagementServiceUri(IServiceProvider provider)
|
||||
{
|
||||
var azureEnvironment = provider.GetRequiredService<AzureEnvironment>();
|
||||
var serviceName = provider.GetRequiredService<ManagementServiceName>();
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
|
||||
var apiVersion = configuration.TryGetValue("ARM_API_VERSION")
|
||||
.IfNone(() => "2022-08-01");
|
||||
|
||||
var uri = azureEnvironment.ManagementEndpoint
|
||||
.AppendPathSegment("subscriptions")
|
||||
.AppendPathSegment(configuration.GetValue("AZURE_SUBSCRIPTION_ID"))
|
||||
.AppendPathSegment("resourceGroups")
|
||||
.AppendPathSegment(configuration.GetValue("AZURE_RESOURCE_GROUP_NAME"))
|
||||
.AppendPathSegment("providers/Microsoft.ApiManagement/service")
|
||||
.AppendPathSegment(serviceName.ToString())
|
||||
.SetQueryParam("api-version", apiVersion)
|
||||
.ToUri();
|
||||
|
||||
return ManagementServiceUri.From(uri);
|
||||
}
|
||||
|
||||
public static void ConfigureManagementServiceDirectory(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton(GetManagementServiceDirectory);
|
||||
}
|
||||
|
||||
private static ManagementServiceDirectory GetManagementServiceDirectory(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
var directoryPath = configuration.GetValue("API_MANAGEMENT_SERVICE_OUTPUT_FOLDER_PATH");
|
||||
var directory = new DirectoryInfo(directoryPath);
|
||||
|
||||
return ManagementServiceDirectory.From(directory);
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractFactory(IServiceCollection services)
|
||||
{
|
||||
ConfigureConfigurationJson(services);
|
||||
|
||||
services.TryAddSingleton(GetShouldExtractFactory);
|
||||
}
|
||||
|
||||
private static ShouldExtractFactory GetShouldExtractFactory(IServiceProvider provider)
|
||||
{
|
||||
var configurationJson = provider.GetRequiredService<ConfigurationJson>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
return new ShouldExtractFactory(configurationJson, loggerFactory);
|
||||
}
|
||||
|
||||
private static void ConfigureConfigurationJson(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton(GetConfigurationJson);
|
||||
}
|
||||
|
||||
private static ConfigurationJson GetConfigurationJson(IServiceProvider provider)
|
||||
{
|
||||
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||
var configurationJson = ConfigurationJson.From(configuration);
|
||||
|
||||
return GetConfigurationJsonFromYaml(configuration)
|
||||
.Map(configurationJson.MergeWith)
|
||||
.IfNone(configurationJson);
|
||||
}
|
||||
|
||||
private static Option<ConfigurationJson> GetConfigurationJsonFromYaml(IConfiguration configuration) =>
|
||||
configuration.TryGetValue("CONFIGURATION_YAML_PATH")
|
||||
.Map(path => new FileInfo(path))
|
||||
.Where(file => file.Exists)
|
||||
.Map(file =>
|
||||
{
|
||||
using var reader = File.OpenText(file.FullName);
|
||||
return ConfigurationJson.FromYaml(reader);
|
||||
});
|
||||
}
|
|
@ -3,58 +3,64 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractDiagnostics(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractDiagnostics(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(DiagnosticName Name, DiagnosticDto Dto)> ListDiagnostics(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractDiagnostic(DiagnosticName name, DiagnosticDto dto);
|
||||
public delegate ValueTask WriteDiagnosticArtifacts(DiagnosticName name, DiagnosticDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteDiagnosticInformationFile(DiagnosticName name, DiagnosticDto dto, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate IAsyncEnumerable<(DiagnosticName Name, DiagnosticDto Dto)> ListDiagnostics(CancellationToken cancellationToken);
|
||||
|
||||
internal delegate bool ShouldExtractDiagnostic(DiagnosticName name, DiagnosticDto dto);
|
||||
|
||||
internal delegate ValueTask WriteDiagnosticArtifacts(DiagnosticName name, DiagnosticDto dto, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteDiagnosticInformationFile(DiagnosticName name, DiagnosticDto dto, CancellationToken cancellationToken);
|
||||
|
||||
internal static class DiagnosticServices
|
||||
internal static class DiagnosticModule
|
||||
{
|
||||
public static void ConfigureExtractDiagnostics(IServiceCollection services)
|
||||
public static void ConfigureExtractDiagnostics(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListDiagnostics(services);
|
||||
ConfigureShouldExtractDiagnostic(services);
|
||||
ConfigureWriteDiagnosticArtifacts(services);
|
||||
ConfigureListDiagnostics(builder);
|
||||
ConfigureShouldExtractDiagnostic(builder);
|
||||
ConfigureWriteDiagnosticArtifacts(builder);
|
||||
|
||||
services.TryAddSingleton(ExtractDiagnostics);
|
||||
builder.Services.TryAddSingleton(GetExtractDiagnostics);
|
||||
}
|
||||
|
||||
private static ExtractDiagnostics ExtractDiagnostics(IServiceProvider provider)
|
||||
private static ExtractDiagnostics GetExtractDiagnostics(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListDiagnostics>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractDiagnostic>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteDiagnosticArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractDiagnostics));
|
||||
|
||||
logger.LogInformation("Extracting diagnostics...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(diagnostic => shouldExtract(diagnostic.Name, diagnostic.Dto))
|
||||
.IterParallel(async diagnostic => await writeArtifacts(diagnostic.Name, diagnostic.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListDiagnostics(IServiceCollection services)
|
||||
private static void ConfigureListDiagnostics(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceUri(services);
|
||||
CommonServices.ConfigureHttpPipeline(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton(ListDiagnostics);
|
||||
builder.Services.TryAddSingleton(GetListDiagnostics);
|
||||
}
|
||||
|
||||
private static ListDiagnostics ListDiagnostics(IServiceProvider provider)
|
||||
private static ListDiagnostics GetListDiagnostics(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
@ -64,15 +70,15 @@ internal static class DiagnosticServices
|
|||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractDiagnostic(IServiceCollection services)
|
||||
private static void ConfigureShouldExtractDiagnostic(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureShouldExtractFactory(services);
|
||||
LoggerServices.ConfigureShouldExtractLogger(services);
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
LoggerModule.ConfigureShouldExtractLogger(builder);
|
||||
|
||||
services.TryAddSingleton(ShouldExtractDiagnostic);
|
||||
builder.Services.TryAddSingleton(GetShouldExtractDiagnostic);
|
||||
}
|
||||
|
||||
private static ShouldExtractDiagnostic ShouldExtractDiagnostic(IServiceProvider provider)
|
||||
private static ShouldExtractDiagnostic GetShouldExtractDiagnostic(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
var shouldExtractLogger = provider.GetRequiredService<ShouldExtractLogger>();
|
||||
|
@ -81,19 +87,19 @@ internal static class DiagnosticServices
|
|||
|
||||
return (name, dto) =>
|
||||
shouldExtractDiagnosticName(name)
|
||||
&& DiagnosticModule.TryGetLoggerName(dto)
|
||||
.Map(shouldExtractLogger.Invoke)
|
||||
.IfNone(true);
|
||||
&& common.DiagnosticModule.TryGetLoggerName(dto)
|
||||
.Map(shouldExtractLogger.Invoke)
|
||||
.IfNone(true);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteDiagnosticArtifacts(IServiceCollection services)
|
||||
private static void ConfigureWriteDiagnosticArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteDiagnosticInformationFile(services);
|
||||
ConfigureWriteDiagnosticInformationFile(builder);
|
||||
|
||||
services.TryAddSingleton(WriteDiagnosticArtifacts);
|
||||
builder.Services.TryAddSingleton(GetWriteDiagnosticArtifacts);
|
||||
}
|
||||
|
||||
private static WriteDiagnosticArtifacts WriteDiagnosticArtifacts(IServiceProvider provider)
|
||||
private static WriteDiagnosticArtifacts GetWriteDiagnosticArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteDiagnosticInformationFile>();
|
||||
|
||||
|
@ -101,19 +107,17 @@ internal static class DiagnosticServices
|
|||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteDiagnosticInformationFile(IServiceCollection services)
|
||||
private static void ConfigureWriteDiagnosticInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
CommonServices.ConfigureManagementServiceDirectory(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton(WriteDiagnosticInformationFile);
|
||||
builder.Services.TryAddSingleton(GetWriteDiagnosticInformationFile);
|
||||
}
|
||||
|
||||
private static WriteDiagnosticInformationFile WriteDiagnosticInformationFile(IServiceProvider provider)
|
||||
private static WriteDiagnosticInformationFile GetWriteDiagnosticInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
var logger = Common.GetLogger(loggerFactory);
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
|
@ -123,10 +127,4 @@ internal static class DiagnosticServices
|
|||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("DiagnosticExtractor");
|
||||
}
|
|
@ -3,120 +3,122 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractGateways(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractGateways(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(GatewayName Name, GatewayDto Dto)> ListGateways(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractGateway(GatewayName name);
|
||||
public delegate ValueTask WriteGatewayArtifacts(GatewayName name, GatewayDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteGatewayInformationFile(GatewayName name, GatewayDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(GatewayName Name, GatewayDto Dto)> ListGateways(CancellationToken cancellationToken);
|
||||
|
||||
file delegate bool ShouldExtractGateway(GatewayName name);
|
||||
|
||||
file delegate ValueTask WriteGatewayArtifacts(GatewayName name, GatewayDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteGatewayInformationFile(GatewayName name, GatewayDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractGatewaysHandler(ListGateways list,
|
||||
ShouldExtractGateway shouldExtract,
|
||||
WriteGatewayArtifacts writeArtifacts,
|
||||
ExtractGatewayApis extractGatewayApis)
|
||||
internal static class GatewayModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(gateway => shouldExtract(gateway.Name))
|
||||
.IterParallel(async gateway => await ExtractGateway(gateway.Name, gateway.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
|
||||
private async ValueTask ExtractGateway(GatewayName name, GatewayDto dto, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractGateways(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeArtifacts(name, dto, cancellationToken);
|
||||
await extractGatewayApis(name, cancellationToken);
|
||||
ConfigureListGateways(builder);
|
||||
ConfigureShouldExtractGateway(builder);
|
||||
ConfigureWriteGatewayArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractGateways);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class ListGatewaysHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(GatewayName, GatewayDto)> Handle(CancellationToken cancellationToken) =>
|
||||
GatewaysUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractGatewayHandler(ShouldExtractFactory shouldExtractFactory)
|
||||
{
|
||||
public bool Handle(GatewayName name)
|
||||
private static ExtractGateways GetExtractGateways(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListGateways>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractGateway>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteGatewayArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractGateways));
|
||||
|
||||
logger.LogInformation("Extracting gateways...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(gateway => shouldExtract(gateway.Name))
|
||||
.IterParallel(async gateway => await writeArtifacts(gateway.Name, gateway.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListGateways(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListGateways);
|
||||
}
|
||||
|
||||
private static ListGateways GetListGateways(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
GatewaysUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractGateway(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractGateway);
|
||||
}
|
||||
|
||||
private static ShouldExtractGateway GetShouldExtractGateway(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<GatewayName>();
|
||||
return shouldExtract(name);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteGatewayArtifactsHandler(WriteGatewayInformationFile writeInformationFile)
|
||||
{
|
||||
public async ValueTask Handle(GatewayName name, GatewayDto dto, CancellationToken cancellationToken)
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGatewayArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
ConfigureWriteGatewayInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteGatewayArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteGatewayInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(GatewayName name, GatewayDto dto, CancellationToken cancellationToken)
|
||||
private static WriteGatewayArtifacts GetWriteGatewayArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var informationFile = GatewayInformationFile.From(name, serviceDirectory);
|
||||
var writeInformationFile = provider.GetRequiredService<WriteGatewayInformationFile>();
|
||||
|
||||
logger.LogInformation("Writing gateway information file {InformationFile}", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class GatewayServices
|
||||
{
|
||||
public static void ConfigureExtractGateways(IServiceCollection services)
|
||||
private static void ConfigureWriteGatewayInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListGateways(services);
|
||||
ConfigureShouldExtractGateway(services);
|
||||
ConfigureWriteGatewayArtifacts(services);
|
||||
GatewayApiServices.ConfigureExtractGatewayApis(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton<ExtractGatewaysHandler>();
|
||||
services.TryAddSingleton<ExtractGateways>(provider => provider.GetRequiredService<ExtractGatewaysHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetWriteGatewayInformationFile);
|
||||
}
|
||||
|
||||
private static void ConfigureListGateways(IServiceCollection services)
|
||||
private static WriteGatewayInformationFile GetWriteGatewayInformationFile(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListGatewaysHandler>();
|
||||
services.TryAddSingleton<ListGateways>(provider => provider.GetRequiredService<ListGatewaysHandler>().Handle);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = GatewayInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing gateway information file {GatewayInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractGateway(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<ShouldExtractGatewayHandler>();
|
||||
services.TryAddSingleton<ShouldExtractGateway>(provider => provider.GetRequiredService<ShouldExtractGatewayHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGatewayArtifacts(IServiceCollection services)
|
||||
{
|
||||
ConfigureWriteGatewayInformationFile(services);
|
||||
|
||||
services.TryAddSingleton<WriteGatewayArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteGatewayArtifacts>(provider => provider.GetRequiredService<WriteGatewayArtifactsHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGatewayInformationFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WriteGatewayInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteGatewayInformationFile>(provider => provider.GetRequiredService<WriteGatewayInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("GatewayExtractor");
|
||||
}
|
|
@ -2,93 +2,105 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractGatewayApis(GatewayName gatewayName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractGatewayApis(GatewayName gatewayName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ApiName Name, GatewayApiDto Dto)> ListGatewayApis(GatewayName gatewayName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteGatewayApiArtifacts(ApiName name, GatewayApiDto dto, GatewayName gatewayName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteGatewayApiInformationFile(ApiName name, GatewayApiDto dto, GatewayName gatewayName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(ApiName Name, GatewayApiDto Dto)> ListGatewayApis(GatewayName gatewayName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteGatewayApiArtifacts(ApiName name, GatewayApiDto dto, GatewayName gatewayName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteGatewayApiInformationFile(ApiName name, GatewayApiDto dto, GatewayName gatewayName, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractGatewayApisHandler(ListGatewayApis list, ShouldExtractApiName shouldExtractApi, WriteGatewayApiArtifacts writeArtifacts)
|
||||
internal static class GatewayApiModule
|
||||
{
|
||||
public async ValueTask Handle(GatewayName gatewayName, CancellationToken cancellationToken) =>
|
||||
await list(gatewayName, cancellationToken)
|
||||
.Where(api => shouldExtractApi(api.Name))
|
||||
.IterParallel(async gatewayapi => await writeArtifacts(gatewayapi.Name, gatewayapi.Dto, gatewayName, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListGatewayApisHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(ApiName, GatewayApiDto)> Handle(GatewayName gatewayName, CancellationToken cancellationToken) =>
|
||||
GatewayApisUri.From(gatewayName, serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class WriteGatewayApiArtifactsHandler(WriteGatewayApiInformationFile writeApiFile)
|
||||
{
|
||||
public async ValueTask Handle(ApiName name, GatewayApiDto dto, GatewayName gatewayName, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractGatewayApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeApiFile(name, dto, gatewayName, cancellationToken);
|
||||
}
|
||||
}
|
||||
ConfigureListGatewayApis(builder);
|
||||
ApiModule.ConfigureShouldExtractApiName(builder);
|
||||
ConfigureWriteGatewayApiArtifacts(builder);
|
||||
|
||||
file sealed class WriteGatewayApiInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(ApiName name, GatewayApiDto dto, GatewayName gatewayName, CancellationToken cancellationToken)
|
||||
{
|
||||
var informationFile = GatewayApiInformationFile.From(name, gatewayName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing gateway api information file {GatewayApiInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class GatewayApiServices
|
||||
{
|
||||
public static void ConfigureExtractGatewayApis(IServiceCollection services)
|
||||
{
|
||||
ConfigureListGatewayApis(services);
|
||||
ApiServices.ConfigureShouldExtractApiName(services);
|
||||
ConfigureWriteGatewayApiArtifacts(services);
|
||||
|
||||
services.TryAddSingleton<ExtractGatewayApisHandler>();
|
||||
services.TryAddSingleton<ExtractGatewayApis>(provider => provider.GetRequiredService<ExtractGatewayApisHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetExtractGatewayApis);
|
||||
}
|
||||
|
||||
private static void ConfigureListGatewayApis(IServiceCollection services)
|
||||
private static ExtractGatewayApis GetExtractGatewayApis(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListGatewayApisHandler>();
|
||||
services.TryAddSingleton<ListGatewayApis>(provider => provider.GetRequiredService<ListGatewayApisHandler>().Handle);
|
||||
var list = provider.GetRequiredService<ListGatewayApis>();
|
||||
var shouldExtractApi = provider.GetRequiredService<ShouldExtractApiName>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteGatewayApiArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (gatewayName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractGatewayApis));
|
||||
|
||||
logger.LogInformation("Extracting APIs for gateway {GatewayName}...", gatewayName);
|
||||
|
||||
await list(gatewayName, cancellationToken)
|
||||
.Where(api => shouldExtractApi(api.Name))
|
||||
.IterParallel(async gatewayapi => await writeArtifacts(gatewayapi.Name, gatewayapi.Dto, gatewayName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGatewayApiArtifacts(IServiceCollection services)
|
||||
private static void ConfigureListGatewayApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteGatewayApiInformationFile(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton<WriteGatewayApiArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteGatewayApiArtifacts>(provider => provider.GetRequiredService<WriteGatewayApiArtifactsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetListGatewayApis);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGatewayApiInformationFile(IServiceCollection services)
|
||||
private static ListGatewayApis GetListGatewayApis(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<WriteGatewayApiInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteGatewayApiInformationFile>(provider => provider.GetRequiredService<WriteGatewayApiInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("GatewayApiExtractor");
|
||||
return (gatewayName, cancellationToken) =>
|
||||
GatewayApisUri.From(gatewayName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGatewayApiArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteGatewayApiInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteGatewayApiArtifacts);
|
||||
}
|
||||
|
||||
private static WriteGatewayApiArtifacts GetWriteGatewayApiArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteGatewayApiInformationFile>();
|
||||
|
||||
return async (name, dto, gatewayName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, gatewayName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureWriteGatewayApiInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetWriteGatewayApiInformationFile);
|
||||
}
|
||||
|
||||
private static WriteGatewayApiInformationFile GetWriteGatewayApiInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, gatewayName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = GatewayApiInformationFile.From(name, gatewayName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing gateway API information file {GatewayApiInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -3,110 +3,124 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractGroups(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractGroups(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(GroupName Name, GroupDto Dto)> ListGroups(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractGroup(GroupName name);
|
||||
public delegate ValueTask WriteGroupArtifacts(GroupName name, GroupDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteGroupInformationFile(GroupName name, GroupDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(GroupName Name, GroupDto Dto)> ListGroups(CancellationToken cancellationToken);
|
||||
|
||||
file delegate bool ShouldExtractGroup(GroupName name);
|
||||
|
||||
file delegate ValueTask WriteGroupArtifacts(GroupName name, GroupDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteGroupInformationFile(GroupName name, GroupDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractGroupsHandler(ListGroups list, ShouldExtractGroup shouldExtract, WriteGroupArtifacts writeArtifacts)
|
||||
internal static class GroupModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(group => shouldExtract(group.Name))
|
||||
.IterParallel(async group => await writeArtifacts(group.Name, group.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListGroupsHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(GroupName, GroupDto)> Handle(CancellationToken cancellationToken) =>
|
||||
GroupsUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractGroupHandler(ShouldExtractFactory shouldExtractFactory)
|
||||
{
|
||||
public bool Handle(GroupName name)
|
||||
public static void ConfigureExtractGroups(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListGroups(builder);
|
||||
ConfigureShouldExtractGroup(builder);
|
||||
ConfigureWriteGroupArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractGroups);
|
||||
}
|
||||
|
||||
private static ExtractGroups GetExtractGroups(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListGroups>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractGroup>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteGroupArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractGroups));
|
||||
|
||||
logger.LogInformation("Extracting groups...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(group => shouldExtract(group.Name))
|
||||
.IterParallel(async group => await writeArtifacts(group.Name, group.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListGroups(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListGroups);
|
||||
}
|
||||
|
||||
private static ListGroups GetListGroups(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
GroupsUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractGroup(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractGroup);
|
||||
}
|
||||
|
||||
private static ShouldExtractGroup GetShouldExtractGroup(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<GroupName>();
|
||||
return shouldExtract(name);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteGroupArtifactsHandler(WriteGroupInformationFile writeInformationFile)
|
||||
{
|
||||
public async ValueTask Handle(GroupName name, GroupDto dto, CancellationToken cancellationToken)
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGroupArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
ConfigureWriteGroupInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteGroupArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteGroupInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(GroupName name, GroupDto dto, CancellationToken cancellationToken)
|
||||
private static WriteGroupArtifacts GetWriteGroupArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var informationFile = GroupInformationFile.From(name, serviceDirectory);
|
||||
var writeInformationFile = provider.GetRequiredService<WriteGroupInformationFile>();
|
||||
|
||||
logger.LogInformation("Writing group information file {InformationFile}", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
internal static class GroupServices
|
||||
{
|
||||
public static void ConfigureExtractGroups(IServiceCollection services)
|
||||
private static void ConfigureWriteGroupInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListGroups(services);
|
||||
ConfigureShouldExtractGroup(services);
|
||||
ConfigureWriteGroupArtifacts(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton<ExtractGroupsHandler>();
|
||||
services.TryAddSingleton<ExtractGroups>(provider => provider.GetRequiredService<ExtractGroupsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetWriteGroupInformationFile);
|
||||
}
|
||||
|
||||
private static void ConfigureListGroups(IServiceCollection services)
|
||||
private static WriteGroupInformationFile GetWriteGroupInformationFile(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListGroupsHandler>();
|
||||
services.TryAddSingleton<ListGroups>(provider => provider.GetRequiredService<ListGroupsHandler>().Handle);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = GroupInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing group information file {GroupInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractGroup(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<ShouldExtractGroupHandler>();
|
||||
services.TryAddSingleton<ShouldExtractGroup>(provider => provider.GetRequiredService<ShouldExtractGroupHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGroupArtifacts(IServiceCollection services)
|
||||
{
|
||||
ConfigureWriteGroupInformationFile(services);
|
||||
|
||||
services.TryAddSingleton<WriteGroupArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteGroupArtifacts>(provider => provider.GetRequiredService<WriteGroupArtifactsHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteGroupInformationFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WriteGroupInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteGroupInformationFile>(provider => provider.GetRequiredService<WriteGroupInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("GroupExtractor");
|
||||
}
|
|
@ -3,110 +3,122 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractLoggers(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractLoggers(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(LoggerName Name, LoggerDto Dto)> ListLoggers(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractLogger(LoggerName name);
|
||||
public delegate ValueTask WriteLoggerArtifacts(LoggerName name, LoggerDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteLoggerInformationFile(LoggerName name, LoggerDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(LoggerName Name, LoggerDto Dto)> ListLoggers(CancellationToken cancellationToken);
|
||||
|
||||
internal delegate bool ShouldExtractLogger(LoggerName name);
|
||||
|
||||
file delegate ValueTask WriteLoggerArtifacts(LoggerName name, LoggerDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteLoggerInformationFile(LoggerName name, LoggerDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractLoggersHandler(ListLoggers list, ShouldExtractLogger shouldExtract, WriteLoggerArtifacts writeArtifacts)
|
||||
internal static class LoggerModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(logger => shouldExtract(logger.Name))
|
||||
.IterParallel(async logger => await writeArtifacts(logger.Name, logger.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListLoggersHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(LoggerName, LoggerDto)> Handle(CancellationToken cancellationToken) =>
|
||||
LoggersUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractLoggerHandler(ShouldExtractFactory shouldExtractFactory)
|
||||
{
|
||||
public bool Handle(LoggerName name)
|
||||
public static void ConfigureExtractLoggers(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListLoggers(builder);
|
||||
ConfigureShouldExtractLogger(builder);
|
||||
ConfigureWriteLoggerArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractLoggers);
|
||||
}
|
||||
|
||||
private static ExtractLoggers GetExtractLoggers(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListLoggers>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractLogger>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteLoggerArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractLoggers));
|
||||
|
||||
logger.LogInformation("Extracting loggers...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(logger => shouldExtract(logger.Name))
|
||||
.IterParallel(async logger => await writeArtifacts(logger.Name, logger.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListLoggers(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListLoggers);
|
||||
}
|
||||
|
||||
private static ListLoggers GetListLoggers(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
LoggersUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractLogger(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractLogger);
|
||||
}
|
||||
|
||||
private static ShouldExtractLogger GetShouldExtractLogger(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<LoggerName>();
|
||||
return shouldExtract(name);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteLoggerArtifactsHandler(WriteLoggerInformationFile writeInformationFile)
|
||||
{
|
||||
public async ValueTask Handle(LoggerName name, LoggerDto dto, CancellationToken cancellationToken)
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteLoggerArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
ConfigureWriteLoggerInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteLoggerArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteLoggerInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(LoggerName name, LoggerDto dto, CancellationToken cancellationToken)
|
||||
private static WriteLoggerArtifacts GetWriteLoggerArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var informationFile = LoggerInformationFile.From(name, serviceDirectory);
|
||||
var writeInformationFile = provider.GetRequiredService<WriteLoggerInformationFile>();
|
||||
|
||||
logger.LogInformation("Writing logger information file {InformationFile}", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class LoggerServices
|
||||
{
|
||||
public static void ConfigureExtractLoggers(IServiceCollection services)
|
||||
private static void ConfigureWriteLoggerInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListLoggers(services);
|
||||
ConfigureShouldExtractLogger(services);
|
||||
ConfigureWriteLoggerArtifacts(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton<ExtractLoggersHandler>();
|
||||
services.TryAddSingleton<ExtractLoggers>(provider => provider.GetRequiredService<ExtractLoggersHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetWriteLoggerInformationFile);
|
||||
}
|
||||
|
||||
private static void ConfigureListLoggers(IServiceCollection services)
|
||||
private static WriteLoggerInformationFile GetWriteLoggerInformationFile(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListLoggersHandler>();
|
||||
services.TryAddSingleton<ListLoggers>(provider => provider.GetRequiredService<ListLoggersHandler>().Handle);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = LoggerInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing logger information file {LoggerInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractLogger(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<ShouldExtractLoggerHandler>();
|
||||
services.TryAddSingleton<ShouldExtractLogger>(provider => provider.GetRequiredService<ShouldExtractLoggerHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteLoggerArtifacts(IServiceCollection services)
|
||||
{
|
||||
ConfigureWriteLoggerInformationFile(services);
|
||||
|
||||
services.TryAddSingleton<WriteLoggerArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteLoggerArtifacts>(provider => provider.GetRequiredService<WriteLoggerArtifactsHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteLoggerInformationFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WriteLoggerInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteLoggerInformationFile>(provider => provider.GetRequiredService<WriteLoggerInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("LoggerExtractor");
|
||||
}
|
|
@ -3,110 +3,122 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractNamedValues(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractNamedValues(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(NamedValueName Name, NamedValueDto Dto)> ListNamedValues(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractNamedValue(NamedValueName name);
|
||||
public delegate ValueTask WriteNamedValueArtifacts(NamedValueName name, NamedValueDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteNamedValueInformationFile(NamedValueName name, NamedValueDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(NamedValueName Name, NamedValueDto Dto)> ListNamedValues(CancellationToken cancellationToken);
|
||||
|
||||
file delegate bool ShouldExtractNamedValue(NamedValueName name);
|
||||
|
||||
file delegate ValueTask WriteNamedValueArtifacts(NamedValueName name, NamedValueDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteNamedValueInformationFile(NamedValueName name, NamedValueDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractNamedValuesHandler(ListNamedValues list, ShouldExtractNamedValue shouldExtract, WriteNamedValueArtifacts writeArtifacts)
|
||||
internal static class NamedValueModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(namedvalue => shouldExtract(namedvalue.Name))
|
||||
.IterParallel(async namedvalue => await writeArtifacts(namedvalue.Name, namedvalue.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListNamedValuesHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(NamedValueName, NamedValueDto)> Handle(CancellationToken cancellationToken) =>
|
||||
NamedValuesUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractNamedValueHandler(ShouldExtractFactory shouldExtractFactory)
|
||||
{
|
||||
public bool Handle(NamedValueName name)
|
||||
public static void ConfigureExtractNamedValues(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListNamedValues(builder);
|
||||
ConfigureShouldExtractNamedValue(builder);
|
||||
ConfigureWriteNamedValueArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractNamedValues);
|
||||
}
|
||||
|
||||
private static ExtractNamedValues GetExtractNamedValues(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListNamedValues>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractNamedValue>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteNamedValueArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractNamedValues));
|
||||
|
||||
logger.LogInformation("Extracting named values...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(namedvalue => shouldExtract(namedvalue.Name))
|
||||
.IterParallel(async namedvalue => await writeArtifacts(namedvalue.Name, namedvalue.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListNamedValues(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListNamedValues);
|
||||
}
|
||||
|
||||
private static ListNamedValues GetListNamedValues(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
NamedValuesUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractNamedValue(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractNamedValue);
|
||||
}
|
||||
|
||||
private static ShouldExtractNamedValue GetShouldExtractNamedValue(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<NamedValueName>();
|
||||
return shouldExtract(name);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteNamedValueArtifactsHandler(WriteNamedValueInformationFile writeInformationFile)
|
||||
{
|
||||
public async ValueTask Handle(NamedValueName name, NamedValueDto dto, CancellationToken cancellationToken)
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteNamedValueArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
ConfigureWriteNamedValueInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteNamedValueArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteNamedValueInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(NamedValueName name, NamedValueDto dto, CancellationToken cancellationToken)
|
||||
private static WriteNamedValueArtifacts GetWriteNamedValueArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var informationFile = NamedValueInformationFile.From(name, serviceDirectory);
|
||||
var writeInformationFile = provider.GetRequiredService<WriteNamedValueInformationFile>();
|
||||
|
||||
logger.LogInformation("Writing named value information file {NamedValueInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class NamedValueServices
|
||||
{
|
||||
public static void ConfigureExtractNamedValues(IServiceCollection services)
|
||||
private static void ConfigureWriteNamedValueInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListNamedValues(services);
|
||||
ConfigureShouldExtractNamedValue(services);
|
||||
ConfigureWriteNamedValueArtifacts(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton<ExtractNamedValuesHandler>();
|
||||
services.TryAddSingleton<ExtractNamedValues>(provider => provider.GetRequiredService<ExtractNamedValuesHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetWriteNamedValueInformationFile);
|
||||
}
|
||||
|
||||
private static void ConfigureListNamedValues(IServiceCollection services)
|
||||
private static WriteNamedValueInformationFile GetWriteNamedValueInformationFile(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListNamedValuesHandler>();
|
||||
services.TryAddSingleton<ListNamedValues>(provider => provider.GetRequiredService<ListNamedValuesHandler>().Handle);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = NamedValueInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing named value information file {NamedValueInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractNamedValue(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<ShouldExtractNamedValueHandler>();
|
||||
services.TryAddSingleton<ShouldExtractNamedValue>(provider => provider.GetRequiredService<ShouldExtractNamedValueHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteNamedValueArtifacts(IServiceCollection services)
|
||||
{
|
||||
ConfigureWriteNamedValueInformationFile(services);
|
||||
|
||||
services.TryAddSingleton<WriteNamedValueArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteNamedValueArtifacts>(provider => provider.GetRequiredService<WriteNamedValueArtifactsHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteNamedValueInformationFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WriteNamedValueInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteNamedValueInformationFile>(provider => provider.GetRequiredService<WriteNamedValueInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("NamedValueExtractor");
|
||||
}
|
|
@ -3,135 +3,153 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractPolicyFragments(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractPolicyFragments(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(PolicyFragmentName Name, PolicyFragmentDto Dto)> ListPolicyFragments(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractPolicyFragment(PolicyFragmentName name);
|
||||
public delegate ValueTask WritePolicyFragmentArtifacts(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WritePolicyFragmentInformationFile(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WritePolicyFragmentPolicyFile(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(PolicyFragmentName Name, PolicyFragmentDto Dto)> ListPolicyFragments(CancellationToken cancellationToken);
|
||||
|
||||
file delegate bool ShouldExtractPolicyFragment(PolicyFragmentName name);
|
||||
|
||||
file delegate ValueTask WritePolicyFragmentArtifacts(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WritePolicyFragmentInformationFile(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WritePolicyFragmentPolicyFile(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractPolicyFragmentsHandler(ListPolicyFragments list, ShouldExtractPolicyFragment shouldExtract, WritePolicyFragmentArtifacts writeArtifacts)
|
||||
internal static class PolicyFragmentModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(policyfragment => shouldExtract(policyfragment.Name))
|
||||
.IterParallel(async policyfragment => await writeArtifacts(policyfragment.Name, policyfragment.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListPolicyFragmentsHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(PolicyFragmentName, PolicyFragmentDto)> Handle(CancellationToken cancellationToken) =>
|
||||
PolicyFragmentsUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractPolicyFragmentHandler(ShouldExtractFactory shouldExtractFactory)
|
||||
{
|
||||
public bool Handle(PolicyFragmentName name)
|
||||
public static void ConfigureExtractPolicyFragments(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListPolicyFragments(builder);
|
||||
ConfigureShouldExtractPolicyFragment(builder);
|
||||
ConfigureWritePolicyFragmentArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractPolicyFragments);
|
||||
}
|
||||
|
||||
private static ExtractPolicyFragments GetExtractPolicyFragments(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListPolicyFragments>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractPolicyFragment>();
|
||||
var writeArtifacts = provider.GetRequiredService<WritePolicyFragmentArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractPolicyFragments));
|
||||
|
||||
logger.LogInformation("Extracting policy fragments...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(policyfragment => shouldExtract(policyfragment.Name))
|
||||
.IterParallel(async policyfragment => await writeArtifacts(policyfragment.Name, policyfragment.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListPolicyFragments(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListPolicyFragments);
|
||||
}
|
||||
|
||||
private static ListPolicyFragments GetListPolicyFragments(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
PolicyFragmentsUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractPolicyFragment(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractPolicyFragment);
|
||||
}
|
||||
|
||||
private static ShouldExtractPolicyFragment GetShouldExtractPolicyFragment(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<PolicyFragmentName>();
|
||||
return shouldExtract(name);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WritePolicyFragmentArtifactsHandler(WritePolicyFragmentInformationFile writeInformationFile,
|
||||
WritePolicyFragmentPolicyFile writePolicyFragmentPolicyFile)
|
||||
{
|
||||
public async ValueTask Handle(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken)
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWritePolicyFragmentArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
await writePolicyFragmentPolicyFile(name, dto, cancellationToken);
|
||||
ConfigureWritePolicyFragmentInformationFile(builder);
|
||||
ConfigureWritePolicyFragmentPolicyFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWritePolicyFragmentArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WritePolicyFragmentInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken)
|
||||
private static WritePolicyFragmentArtifacts GetWritePolicyFragmentArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var informationFile = PolicyFragmentInformationFile.From(name, serviceDirectory);
|
||||
var writeInformationFile = provider.GetRequiredService<WritePolicyFragmentInformationFile>();
|
||||
var writePolicyFragmentPolicyFile = provider.GetRequiredService<WritePolicyFragmentPolicyFile>();
|
||||
|
||||
logger.LogInformation("Writing policy fragment information file {PolicyFragmentInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
await writePolicyFragmentPolicyFile(name, dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WritePolicyFragmentPolicyFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(PolicyFragmentName name, PolicyFragmentDto dto, CancellationToken cancellationToken)
|
||||
private static void ConfigureWritePolicyFragmentInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
var policyFile = PolicyFragmentPolicyFile.From(name, serviceDirectory);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
logger.LogInformation("Writing policy fragment policy file {PolicyFragmentPolicyFile}...", policyFile);
|
||||
var policy = dto.Properties.Value ?? string.Empty;
|
||||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
builder.Services.TryAddSingleton(GetWritePolicyFragmentInformationFile);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class PolicyFragmentServices
|
||||
{
|
||||
public static void ConfigureExtractPolicyFragments(IServiceCollection services)
|
||||
private static WritePolicyFragmentInformationFile GetWritePolicyFragmentInformationFile(IServiceProvider provider)
|
||||
{
|
||||
ConfigureListPolicyFragments(services);
|
||||
ConfigureShouldExtractPolicyFragment(services);
|
||||
ConfigureWritePolicyFragmentArtifacts(services);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
services.TryAddSingleton<ExtractPolicyFragmentsHandler>();
|
||||
services.TryAddSingleton<ExtractPolicyFragments>(provider => provider.GetRequiredService<ExtractPolicyFragmentsHandler>().Handle);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = PolicyFragmentInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing policy fragment information file {PolicyFragmentInformationFile}...", informationFile);
|
||||
|
||||
// Remove policy contents from DTO, as these will be written to the policy file
|
||||
var updatedDto = dto with { Properties = dto.Properties with { Format = null, Value = null } };
|
||||
await informationFile.WriteDto(updatedDto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListPolicyFragments(IServiceCollection services)
|
||||
private static void ConfigureWritePolicyFragmentPolicyFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
services.TryAddSingleton<ListPolicyFragmentsHandler>();
|
||||
services.TryAddSingleton<ListPolicyFragments>(provider => provider.GetRequiredService<ListPolicyFragmentsHandler>().Handle);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWritePolicyFragmentPolicyFile);
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractPolicyFragment(IServiceCollection services)
|
||||
private static WritePolicyFragmentPolicyFile GetWritePolicyFragmentPolicyFile(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ShouldExtractPolicyFragmentHandler>();
|
||||
services.TryAddSingleton<ShouldExtractPolicyFragment>(provider => provider.GetRequiredService<ShouldExtractPolicyFragmentHandler>().Handle);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var policyFile = PolicyFragmentPolicyFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing policy fragment policy file {PolicyFragmentPolicyFile}...", policyFile);
|
||||
var policy = dto.Properties.Value ?? string.Empty;
|
||||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWritePolicyFragmentArtifacts(IServiceCollection services)
|
||||
{
|
||||
ConfigureWritePolicyFragmentInformationFile(services);
|
||||
ConfigureWritePolicyFragmentPolicyFile(services);
|
||||
|
||||
services.TryAddSingleton<WritePolicyFragmentArtifactsHandler>();
|
||||
services.TryAddSingleton<WritePolicyFragmentArtifacts>(provider => provider.GetRequiredService<WritePolicyFragmentArtifactsHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWritePolicyFragmentInformationFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WritePolicyFragmentInformationFileHandler>();
|
||||
services.TryAddSingleton<WritePolicyFragmentInformationFile>(provider => provider.GetRequiredService<WritePolicyFragmentInformationFileHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWritePolicyFragmentPolicyFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WritePolicyFragmentPolicyFileHandler>();
|
||||
services.TryAddSingleton<WritePolicyFragmentPolicyFile>(provider => provider.GetRequiredService<WritePolicyFragmentPolicyFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("PolicyFragmentExtractor");
|
||||
}
|
|
@ -3,129 +3,139 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractProducts(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractProducts(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ProductName Name, ProductDto Dto)> ListProducts(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractProduct(ProductName name);
|
||||
public delegate ValueTask WriteProductArtifacts(ProductName name, ProductDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductInformationFile(ProductName name, ProductDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(ProductName Name, ProductDto Dto)> ListProducts(CancellationToken cancellationToken);
|
||||
|
||||
internal delegate bool ShouldExtractProduct(ProductName name);
|
||||
|
||||
file delegate ValueTask WriteProductArtifacts(ProductName name, ProductDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductInformationFile(ProductName name, ProductDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractProductsHandler(ListProducts list,
|
||||
ShouldExtractProduct shouldExtract,
|
||||
WriteProductArtifacts writeArtifacts,
|
||||
ExtractProductPolicies extractProductPolicies,
|
||||
ExtractProductGroups extractProductGroups,
|
||||
ExtractProductTags extractProductTags,
|
||||
ExtractProductApis extractProductApis)
|
||||
internal static class ProductModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(product => shouldExtract(product.Name))
|
||||
.IterParallel(async product => await ExtractProduct(product.Name, product.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
|
||||
private async ValueTask ExtractProduct(ProductName name, ProductDto dto, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractProducts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeArtifacts(name, dto, cancellationToken);
|
||||
await extractProductPolicies(name, cancellationToken);
|
||||
await extractProductGroups(name, cancellationToken);
|
||||
await extractProductTags(name, cancellationToken);
|
||||
await extractProductApis(name, cancellationToken);
|
||||
ConfigureListProducts(builder);
|
||||
ConfigureShouldExtractProduct(builder);
|
||||
ProductPolicyModule.ConfigureExtractProductPolicies(builder);
|
||||
ProductGroupModule.ConfigureExtractProductGroups(builder);
|
||||
ProductTagModule.ConfigureExtractProductTags(builder);
|
||||
ProductApiModule.ConfigureExtractProductApis(builder);
|
||||
ConfigureWriteProductArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractProducts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class ListProductsHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(ProductName, ProductDto)> Handle(CancellationToken cancellationToken) =>
|
||||
ProductsUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractProductHandler(ShouldExtractFactory shouldExtractFactory)
|
||||
{
|
||||
public bool Handle(ProductName name)
|
||||
private static ExtractProducts GetExtractProducts(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListProducts>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractProduct>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteProductArtifacts>();
|
||||
var extractProductPolicies = provider.GetRequiredService<ExtractProductPolicies>();
|
||||
var extractProductGroups = provider.GetRequiredService<ExtractProductGroups>();
|
||||
var extractProductTags = provider.GetRequiredService<ExtractProductTags>();
|
||||
var extractProductApis = provider.GetRequiredService<ExtractProductApis>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractProducts));
|
||||
|
||||
logger.LogInformation("Extracting products...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(product => shouldExtract(product.Name))
|
||||
.IterParallel(async product => await extractProduct(product.Name, product.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
|
||||
async ValueTask extractProduct(ProductName name, ProductDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
await writeArtifacts(name, dto, cancellationToken);
|
||||
await extractProductPolicies(name, cancellationToken);
|
||||
await extractProductGroups(name, cancellationToken);
|
||||
await extractProductTags(name, cancellationToken);
|
||||
await extractProductApis(name, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConfigureListProducts(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListProducts);
|
||||
}
|
||||
|
||||
private static ListProducts GetListProducts(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
ProductsUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractProduct(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractProduct);
|
||||
}
|
||||
|
||||
private static ShouldExtractProduct GetShouldExtractProduct(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<ProductName>();
|
||||
return shouldExtract(name);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteProductArtifactsHandler(WriteProductInformationFile writeInformationFile)
|
||||
{
|
||||
public async ValueTask Handle(ProductName name, ProductDto dto, CancellationToken cancellationToken)
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
ConfigureWriteProductInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteProductArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteProductInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(ProductName name, ProductDto dto, CancellationToken cancellationToken)
|
||||
private static WriteProductArtifacts GetWriteProductArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var informationFile = ProductInformationFile.From(name, serviceDirectory);
|
||||
var writeInformationFile = provider.GetRequiredService<WriteProductInformationFile>();
|
||||
|
||||
logger.LogInformation("Writing product information file {InformationFile}", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ProductServices
|
||||
{
|
||||
public static void ConfigureExtractProducts(IServiceCollection services)
|
||||
private static void ConfigureWriteProductInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListProducts(services);
|
||||
ConfigureShouldExtractProduct(services);
|
||||
ConfigureWriteProductArtifacts(services);
|
||||
ProductPolicyServices.ConfigureExtractProductPolicies(services);
|
||||
ProductGroupServices.ConfigureExtractProductGroups(services);
|
||||
ProductTagServices.ConfigureExtractProductTags(services);
|
||||
ProductApiServices.ConfigureExtractProductApis(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton<ExtractProductsHandler>();
|
||||
services.TryAddSingleton<ExtractProducts>(provider => provider.GetRequiredService<ExtractProductsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetWriteProductInformationFile);
|
||||
}
|
||||
|
||||
private static void ConfigureListProducts(IServiceCollection services)
|
||||
private static WriteProductInformationFile GetWriteProductInformationFile(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListProductsHandler>();
|
||||
services.TryAddSingleton<ListProducts>(provider => provider.GetRequiredService<ListProductsHandler>().Handle);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = ProductInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product information file {ProductInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractProduct(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<ShouldExtractProductHandler>();
|
||||
services.TryAddSingleton<ShouldExtractProduct>(provider => provider.GetRequiredService<ShouldExtractProductHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductArtifacts(IServiceCollection services)
|
||||
{
|
||||
ConfigureWriteProductInformationFile(services);
|
||||
|
||||
services.TryAddSingleton<WriteProductArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteProductArtifacts>(provider => provider.GetRequiredService<WriteProductArtifactsHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductInformationFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WriteProductInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteProductInformationFile>(provider => provider.GetRequiredService<WriteProductInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ProductExtractor");
|
||||
}
|
|
@ -2,93 +2,105 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractProductApis(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractProductApis(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ApiName Name, ProductApiDto Dto)> ListProductApis(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductApiArtifacts(ApiName name, ProductApiDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductApiInformationFile(ApiName name, ProductApiDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(ApiName Name, ProductApiDto Dto)> ListProductApis(ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductApiArtifacts(ApiName name, ProductApiDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductApiInformationFile(ApiName name, ProductApiDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractProductApisHandler(ListProductApis list, ShouldExtractApiName shouldExtractApi, WriteProductApiArtifacts writeArtifacts)
|
||||
internal static class ProductApiModule
|
||||
{
|
||||
public async ValueTask Handle(ProductName productName, CancellationToken cancellationToken) =>
|
||||
await list(productName, cancellationToken)
|
||||
.Where(api => shouldExtractApi(api.Name))
|
||||
.IterParallel(async productapi => await writeArtifacts(productapi.Name, productapi.Dto, productName, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListProductApisHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(ApiName, ProductApiDto)> Handle(ProductName productName, CancellationToken cancellationToken) =>
|
||||
ProductApisUri.From(productName, serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class WriteProductApiArtifactsHandler(WriteProductApiInformationFile writeApiFile)
|
||||
{
|
||||
public async ValueTask Handle(ApiName name, ProductApiDto dto, ProductName productName, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractProductApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeApiFile(name, dto, productName, cancellationToken);
|
||||
}
|
||||
}
|
||||
ConfigureListProductApis(builder);
|
||||
ApiModule.ConfigureShouldExtractApiName(builder);
|
||||
ConfigureWriteProductApiArtifacts(builder);
|
||||
|
||||
file sealed class WriteProductApiInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(ApiName name, ProductApiDto dto, ProductName productName, CancellationToken cancellationToken)
|
||||
{
|
||||
var informationFile = ProductApiInformationFile.From(name, productName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product api information file {ProductApiInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ProductApiServices
|
||||
{
|
||||
public static void ConfigureExtractProductApis(IServiceCollection services)
|
||||
{
|
||||
ConfigureListProductApis(services);
|
||||
ConfigureWriteProductApiArtifacts(services);
|
||||
ApiServices.ConfigureShouldExtractApiName(services);
|
||||
|
||||
services.TryAddSingleton<ExtractProductApisHandler>();
|
||||
services.TryAddSingleton<ExtractProductApis>(provider => provider.GetRequiredService<ExtractProductApisHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetExtractProductApis);
|
||||
}
|
||||
|
||||
private static void ConfigureListProductApis(IServiceCollection services)
|
||||
private static ExtractProductApis GetExtractProductApis(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListProductApisHandler>();
|
||||
services.TryAddSingleton<ListProductApis>(provider => provider.GetRequiredService<ListProductApisHandler>().Handle);
|
||||
var list = provider.GetRequiredService<ListProductApis>();
|
||||
var shouldExtractApi = provider.GetRequiredService<ShouldExtractApiName>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteProductApiArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (productName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractProductApis));
|
||||
|
||||
logger.LogInformation("Extracting APIs for product {ProductName}...", productName);
|
||||
|
||||
await list(productName, cancellationToken)
|
||||
.Where(api => shouldExtractApi(api.Name))
|
||||
.IterParallel(async productapi => await writeArtifacts(productapi.Name, productapi.Dto, productName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductApiArtifacts(IServiceCollection services)
|
||||
private static void ConfigureListProductApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteProductApiInformationFile(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton<WriteProductApiArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteProductApiArtifacts>(provider => provider.GetRequiredService<WriteProductApiArtifactsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetListProductApis);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductApiInformationFile(IServiceCollection services)
|
||||
private static ListProductApis GetListProductApis(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<WriteProductApiInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteProductApiInformationFile>(provider => provider.GetRequiredService<WriteProductApiInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ProductApiExtractor");
|
||||
return (productName, cancellationToken) =>
|
||||
ProductApisUri.From(productName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductApiArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteProductApiInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteProductApiArtifacts);
|
||||
}
|
||||
|
||||
private static WriteProductApiArtifacts GetWriteProductApiArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteProductApiInformationFile>();
|
||||
|
||||
return async (name, dto, productName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, productName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureWriteProductApiInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetWriteProductApiInformationFile);
|
||||
}
|
||||
|
||||
private static WriteProductApiInformationFile GetWriteProductApiInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, productName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = ProductApiInformationFile.From(name, productName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product API information file {ProductApiInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,90 +2,105 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractProductGroups(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractProductGroups(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(GroupName Name, ProductGroupDto Dto)> ListProductGroups(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductGroupArtifacts(GroupName name, ProductGroupDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductGroupInformationFile(GroupName name, ProductGroupDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(GroupName Name, ProductGroupDto Dto)> ListProductGroups(ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductGroupArtifacts(GroupName name, ProductGroupDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductGroupInformationFile(GroupName name, ProductGroupDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractProductGroupsHandler(ListProductGroups list, WriteProductGroupArtifacts writeArtifacts)
|
||||
internal static class ProductGroupModule
|
||||
{
|
||||
public async ValueTask Handle(ProductName productName, CancellationToken cancellationToken) =>
|
||||
await list(productName, cancellationToken)
|
||||
.IterParallel(async productgroup => await writeArtifacts(productgroup.Name, productgroup.Dto, productName, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListProductGroupsHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(GroupName, ProductGroupDto)> Handle(ProductName productName, CancellationToken cancellationToken) =>
|
||||
ProductGroupsUri.From(productName, serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class WriteProductGroupArtifactsHandler(WriteProductGroupInformationFile writeGroupFile)
|
||||
{
|
||||
public async ValueTask Handle(GroupName name, ProductGroupDto dto, ProductName productName, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractProductGroups(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeGroupFile(name, dto, productName, cancellationToken);
|
||||
}
|
||||
}
|
||||
ConfigureListProductGroups(builder);
|
||||
GroupModule.ConfigureShouldExtractGroup(builder);
|
||||
ConfigureWriteProductGroupArtifacts(builder);
|
||||
|
||||
file sealed class WriteProductGroupInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(GroupName name, ProductGroupDto dto, ProductName productName, CancellationToken cancellationToken)
|
||||
{
|
||||
var informationFile = ProductGroupInformationFile.From(name, productName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product group information file {ProductGroupInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ProductGroupServices
|
||||
{
|
||||
public static void ConfigureExtractProductGroups(IServiceCollection services)
|
||||
{
|
||||
ConfigureListProductGroups(services);
|
||||
ConfigureWriteProductGroupArtifacts(services);
|
||||
|
||||
services.TryAddSingleton<ExtractProductGroupsHandler>();
|
||||
services.TryAddSingleton<ExtractProductGroups>(provider => provider.GetRequiredService<ExtractProductGroupsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetExtractProductGroups);
|
||||
}
|
||||
|
||||
private static void ConfigureListProductGroups(IServiceCollection services)
|
||||
private static ExtractProductGroups GetExtractProductGroups(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListProductGroupsHandler>();
|
||||
services.TryAddSingleton<ListProductGroups>(provider => provider.GetRequiredService<ListProductGroupsHandler>().Handle);
|
||||
var list = provider.GetRequiredService<ListProductGroups>();
|
||||
var shouldExtractGroup = provider.GetRequiredService<ShouldExtractGroup>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteProductGroupArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (productName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractProductGroups));
|
||||
|
||||
logger.LogInformation("Extracting groups for product {ProductName}...", productName);
|
||||
|
||||
await list(productName, cancellationToken)
|
||||
.Where(group => shouldExtractGroup(group.Name))
|
||||
.IterParallel(async productgroup => await writeArtifacts(productgroup.Name, productgroup.Dto, productName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductGroupArtifacts(IServiceCollection services)
|
||||
private static void ConfigureListProductGroups(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteProductGroupInformationFile(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton<WriteProductGroupArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteProductGroupArtifacts>(provider => provider.GetRequiredService<WriteProductGroupArtifactsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetListProductGroups);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductGroupInformationFile(IServiceCollection services)
|
||||
private static ListProductGroups GetListProductGroups(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<WriteProductGroupInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteProductGroupInformationFile>(provider => provider.GetRequiredService<WriteProductGroupInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ProductGroupExtractor");
|
||||
return (productName, cancellationToken) =>
|
||||
ProductGroupsUri.From(productName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductGroupArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteProductGroupInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteProductGroupArtifacts);
|
||||
}
|
||||
|
||||
private static WriteProductGroupArtifacts GetWriteProductGroupArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteProductGroupInformationFile>();
|
||||
|
||||
return async (name, dto, productName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, productName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureWriteProductGroupInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetWriteProductGroupInformationFile);
|
||||
}
|
||||
|
||||
private static WriteProductGroupInformationFile GetWriteProductGroupInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, productName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = ProductGroupInformationFile.From(name, productName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product group information file {ProductGroupInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,91 +2,102 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractProductPolicies(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractProductPolicies(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ProductPolicyName Name, ProductPolicyDto Dto)> ListProductPolicies(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductPolicyArtifacts(ProductPolicyName name, ProductPolicyDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductPolicyFile(ProductPolicyName name, ProductPolicyDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(ProductPolicyName Name, ProductPolicyDto Dto)> ListProductPolicies(ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductPolicyArtifacts(ProductPolicyName name, ProductPolicyDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductPolicyFile(ProductPolicyName name, ProductPolicyDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractProductPoliciesHandler(ListProductPolicies list, WriteProductPolicyArtifacts writeArtifacts)
|
||||
internal static class ProductPolicyModule
|
||||
{
|
||||
public async ValueTask Handle(ProductName productName, CancellationToken cancellationToken) =>
|
||||
await list(productName, cancellationToken)
|
||||
.IterParallel(async productpolicy => await writeArtifacts(productpolicy.Name, productpolicy.Dto, productName, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListProductPoliciesHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(ProductPolicyName, ProductPolicyDto)> Handle(ProductName productName, CancellationToken cancellationToken) =>
|
||||
ProductPoliciesUri.From(productName, serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class WriteProductPolicyArtifactsHandler(WriteProductPolicyFile writePolicyFile)
|
||||
{
|
||||
public async ValueTask Handle(ProductPolicyName name, ProductPolicyDto dto, ProductName productName, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractProductPolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writePolicyFile(name, dto, productName, cancellationToken);
|
||||
}
|
||||
}
|
||||
ConfigureListProductPolicies(builder);
|
||||
ConfigureWriteProductPolicyArtifacts(builder);
|
||||
|
||||
file sealed class WriteProductPolicyFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(ProductPolicyName name, ProductPolicyDto dto, ProductName productName, CancellationToken cancellationToken)
|
||||
{
|
||||
var policyFile = ProductPolicyFile.From(name, productName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product policy file {ProductPolicyFile}...", policyFile);
|
||||
var policy = dto.Properties.Value ?? string.Empty;
|
||||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ProductPolicyServices
|
||||
{
|
||||
public static void ConfigureExtractProductPolicies(IServiceCollection services)
|
||||
{
|
||||
ConfigureListProductPolicies(services);
|
||||
ConfigureWriteProductPolicyArtifacts(services);
|
||||
|
||||
services.TryAddSingleton<ExtractProductPoliciesHandler>();
|
||||
services.TryAddSingleton<ExtractProductPolicies>(provider => provider.GetRequiredService<ExtractProductPoliciesHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetExtractProductPolicies);
|
||||
}
|
||||
|
||||
private static void ConfigureListProductPolicies(IServiceCollection services)
|
||||
private static ExtractProductPolicies GetExtractProductPolicies(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListProductPoliciesHandler>();
|
||||
services.TryAddSingleton<ListProductPolicies>(provider => provider.GetRequiredService<ListProductPoliciesHandler>().Handle);
|
||||
var list = provider.GetRequiredService<ListProductPolicies>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteProductPolicyArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (productName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractProductPolicies));
|
||||
|
||||
logger.LogInformation("Extracting policies for product {ProductName}...", productName);
|
||||
|
||||
await list(productName, cancellationToken)
|
||||
.IterParallel(async policy => await writeArtifacts(policy.Name, policy.Dto, productName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductPolicyArtifacts(IServiceCollection services)
|
||||
private static void ConfigureListProductPolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteProductPolicyFile(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton<WriteProductPolicyArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteProductPolicyArtifacts>(provider => provider.GetRequiredService<WriteProductPolicyArtifactsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetListProductPolicies);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductPolicyFile(IServiceCollection services)
|
||||
private static ListProductPolicies GetListProductPolicies(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<WriteProductPolicyFileHandler>();
|
||||
services.TryAddSingleton<WriteProductPolicyFile>(provider => provider.GetRequiredService<WriteProductPolicyFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ProductPolicyExtractor");
|
||||
return (productName, cancellationToken) =>
|
||||
ProductPoliciesUri.From(productName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductPolicyArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteProductPolicyFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteProductPolicyArtifacts);
|
||||
}
|
||||
|
||||
private static WriteProductPolicyArtifacts GetWriteProductPolicyArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writePolicyFile = provider.GetRequiredService<WriteProductPolicyFile>();
|
||||
|
||||
return async (name, dto, productName, cancellationToken) =>
|
||||
await writePolicyFile(name, dto, productName, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductPolicyFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteProductPolicyFile);
|
||||
}
|
||||
|
||||
private static WriteProductPolicyFile GetWriteProductPolicyFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, productName, cancellationToken) =>
|
||||
{
|
||||
var policyFile = ProductPolicyFile.From(name, productName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product policy file {PolicyFile}", policyFile);
|
||||
var policy = dto.Properties.Value ?? string.Empty;
|
||||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,90 +2,107 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractProductTags(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractProductTags(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(TagName Name, ProductTagDto Dto)> ListProductTags(ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductTagArtifacts(TagName name, ProductTagDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteProductTagInformationFile(TagName name, ProductTagDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(TagName Name, ProductTagDto Dto)> ListProductTags(ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductTagArtifacts(TagName name, ProductTagDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteProductTagInformationFile(TagName name, ProductTagDto dto, ProductName productName, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractProductTagsHandler(ListProductTags list, WriteProductTagArtifacts writeArtifacts)
|
||||
internal static class ProductTagModule
|
||||
{
|
||||
public async ValueTask Handle(ProductName productName, CancellationToken cancellationToken) =>
|
||||
await list(productName, cancellationToken)
|
||||
.IterParallel(async producttag => await writeArtifacts(producttag.Name, producttag.Dto, productName, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListProductTagsHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(TagName, ProductTagDto)> Handle(ProductName productName, CancellationToken cancellationToken) =>
|
||||
ProductTagsUri.From(productName, serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class WriteProductTagArtifactsHandler(WriteProductTagInformationFile writeTagFile)
|
||||
{
|
||||
public async ValueTask Handle(TagName name, ProductTagDto dto, ProductName productName, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractProductTags(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeTagFile(name, dto, productName, cancellationToken);
|
||||
}
|
||||
}
|
||||
ConfigureListProductTags(builder);
|
||||
TagModule.ConfigureShouldExtractTag(builder);
|
||||
ConfigureWriteProductTagArtifacts(builder);
|
||||
|
||||
file sealed class WriteProductTagInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(TagName name, ProductTagDto dto, ProductName productName, CancellationToken cancellationToken)
|
||||
{
|
||||
var informationFile = ProductTagInformationFile.From(name, productName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product tag information file {ProductTagInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ProductTagServices
|
||||
{
|
||||
public static void ConfigureExtractProductTags(IServiceCollection services)
|
||||
{
|
||||
ConfigureListProductTags(services);
|
||||
ConfigureWriteProductTagArtifacts(services);
|
||||
|
||||
services.TryAddSingleton<ExtractProductTagsHandler>();
|
||||
services.TryAddSingleton<ExtractProductTags>(provider => provider.GetRequiredService<ExtractProductTagsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetExtractProductTags);
|
||||
}
|
||||
|
||||
private static void ConfigureListProductTags(IServiceCollection services)
|
||||
private static ExtractProductTags GetExtractProductTags(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListProductTagsHandler>();
|
||||
services.TryAddSingleton<ListProductTags>(provider => provider.GetRequiredService<ListProductTagsHandler>().Handle);
|
||||
var list = provider.GetRequiredService<ListProductTags>();
|
||||
var shouldExtractTag = provider.GetRequiredService<ShouldExtractTag>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteProductTagArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (productName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractProductTags));
|
||||
|
||||
logger.LogInformation("Extracting tags for product {ProductName}...", productName);
|
||||
|
||||
await list(productName, cancellationToken)
|
||||
.Where(tag => shouldExtractTag(tag.Name))
|
||||
.IterParallel(async producttag => await writeArtifacts(producttag.Name, producttag.Dto, productName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductTagArtifacts(IServiceCollection services)
|
||||
private static void ConfigureListProductTags(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteProductTagInformationFile(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton<WriteProductTagArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteProductTagArtifacts>(provider => provider.GetRequiredService<WriteProductTagArtifactsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetListProductTags);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductTagInformationFile(IServiceCollection services)
|
||||
private static ListProductTags GetListProductTags(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<WriteProductTagInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteProductTagInformationFile>(provider => provider.GetRequiredService<WriteProductTagInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ProductTagExtractor");
|
||||
return (productName, cancellationToken) =>
|
||||
ProductTagsUri.From(productName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteProductTagArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteProductTagInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteProductTagArtifacts);
|
||||
}
|
||||
|
||||
private static WriteProductTagArtifacts GetWriteProductTagArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteProductTagInformationFile>();
|
||||
|
||||
return async (name, dto, productName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, productName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureWriteProductTagInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteProductTagInformationFile);
|
||||
}
|
||||
|
||||
private static WriteProductTagInformationFile GetWriteProductTagInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, productName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = ProductTagInformationFile.From(name, productName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing product tag information file {ProductTagInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,9 +1,4 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
@ -12,56 +7,6 @@ public static class Program
|
|||
{
|
||||
public static async Task Main(string[] arguments)
|
||||
{
|
||||
var host = Host.CreateDefaultBuilder(arguments)
|
||||
.ConfigureAppConfiguration(ConfigureConfiguration)
|
||||
.ConfigureServices(ConfigureServices)
|
||||
.Build();
|
||||
|
||||
await RunExtractor(host);
|
||||
await HostingModule.RunHost(arguments, "extractor", AppModule.ConfigureRunApplication);
|
||||
}
|
||||
|
||||
private static void ConfigureConfiguration(IConfigurationBuilder builder)
|
||||
{
|
||||
builder.AddUserSecrets(typeof(Program).Assembly);
|
||||
|
||||
var configuration = builder.Build();
|
||||
|
||||
configuration.TryGetValue("CONFIGURATION_YAML_PATH")
|
||||
.Iter(path => builder.AddYamlFile(path));
|
||||
}
|
||||
|
||||
private static void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
CommonServices.Configure(services);
|
||||
AppServices.ConfigureRunExtractor(services);
|
||||
}
|
||||
|
||||
private static async Task RunExtractor(IHost host)
|
||||
{
|
||||
var applicationLifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
|
||||
var cancellationToken = applicationLifetime.ApplicationStopping;
|
||||
await host.StartAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var runExtractor = host.Services.GetRequiredService<RunExtractor>();
|
||||
await runExtractor(cancellationToken);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Environment.ExitCode = -1;
|
||||
LogException(host, exception);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
applicationLifetime.StopApplication();
|
||||
}
|
||||
}
|
||||
|
||||
private static void LogException(IHost host, Exception exception)
|
||||
{
|
||||
var logger = host.Services.GetRequiredService<ILoggerFactory>().CreateLogger(nameof(Program));
|
||||
logger.LogCritical(exception, "Extractor failed with error {ErrorMessage}", exception.Message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,91 +2,102 @@
|
|||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractServicePolicies(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractServicePolicies(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ServicePolicyName Name, ServicePolicyDto Dto)> ListServicePolicies(CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteServicePolicyArtifacts(ServicePolicyName name, ServicePolicyDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteServicePolicyFile(ServicePolicyName name, ServicePolicyDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(ServicePolicyName Name, ServicePolicyDto Dto)> ListServicePolicies(CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteServicePolicyArtifacts(ServicePolicyName name, ServicePolicyDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteServicePolicyFile(ServicePolicyName name, ServicePolicyDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractServicePoliciesHandler(ListServicePolicies list, WriteServicePolicyArtifacts writeArtifacts)
|
||||
internal static class ServicePolicyModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.IterParallel(async servicepolicy => await writeArtifacts(servicepolicy.Name, servicepolicy.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListServicePoliciesHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(ServicePolicyName, ServicePolicyDto)> Handle(CancellationToken cancellationToken) =>
|
||||
ServicePoliciesUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class WriteServicePolicyArtifactsHandler(WriteServicePolicyFile writePolicyFile)
|
||||
{
|
||||
public async ValueTask Handle(ServicePolicyName name, ServicePolicyDto dto, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractServicePolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writePolicyFile(name, dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
ConfigureListServicePolicies(builder);
|
||||
ConfigureWriteServicePolicyArtifacts(builder);
|
||||
|
||||
file sealed class WriteServicePolicyFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(ServicePolicyName name, ServicePolicyDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var policyFile = ServicePolicyFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing service policy file {ServicePolicyFile}...", policyFile);
|
||||
var policy = dto.Properties.Value ?? string.Empty;
|
||||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ServicePolicyServices
|
||||
{
|
||||
public static void ConfigureExtractServicePolicies(IServiceCollection services)
|
||||
{
|
||||
ConfigureListServicePolicies(services);
|
||||
ConfigureWriteServicePolicyArtifacts(services);
|
||||
|
||||
services.TryAddSingleton<ExtractServicePoliciesHandler>();
|
||||
services.TryAddSingleton<ExtractServicePolicies>(provider => provider.GetRequiredService<ExtractServicePoliciesHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetExtractServicePolicies);
|
||||
}
|
||||
|
||||
private static void ConfigureListServicePolicies(IServiceCollection services)
|
||||
private static ExtractServicePolicies GetExtractServicePolicies(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListServicePoliciesHandler>();
|
||||
services.TryAddSingleton<ListServicePolicies>(provider => provider.GetRequiredService<ListServicePoliciesHandler>().Handle);
|
||||
var list = provider.GetRequiredService<ListServicePolicies>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteServicePolicyArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractServicePolicies));
|
||||
|
||||
logger.LogInformation("Extracting service policies...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.IterParallel(async servicepolicy => await writeArtifacts(servicepolicy.Name, servicepolicy.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteServicePolicyArtifacts(IServiceCollection services)
|
||||
private static void ConfigureListServicePolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteServicePolicyFile(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton<WriteServicePolicyArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteServicePolicyArtifacts>(provider => provider.GetRequiredService<WriteServicePolicyArtifactsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetListServicePolicies);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteServicePolicyFile(IServiceCollection services)
|
||||
private static ListServicePolicies GetListServicePolicies(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<WriteServicePolicyFileHandler>();
|
||||
services.TryAddSingleton<WriteServicePolicyFile>(provider => provider.GetRequiredService<WriteServicePolicyFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("ServicePolicyExtractor");
|
||||
return cancellationToken =>
|
||||
ServicePoliciesUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteServicePolicyArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteServicePolicyFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteServicePolicyArtifacts);
|
||||
}
|
||||
|
||||
private static WriteServicePolicyArtifacts GetWriteServicePolicyArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writePolicyFile = provider.GetRequiredService<WriteServicePolicyFile>();
|
||||
|
||||
return async (ServicePolicyName name, ServicePolicyDto dto, CancellationToken cancellationToken) =>
|
||||
{
|
||||
await writePolicyFile(name, dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteServicePolicyFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetWriteServicePolicyFile);
|
||||
}
|
||||
|
||||
private static WriteServicePolicyFile GetWriteServicePolicyFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (ServicePolicyName name, ServicePolicyDto dto, CancellationToken cancellationToken) =>
|
||||
{
|
||||
var policyFile = ServicePolicyFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing service policy file {ServicePolicyFile}...", policyFile);
|
||||
var policy = dto.Properties.Value ?? string.Empty;
|
||||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
using common;
|
||||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
|
@ -14,7 +17,7 @@ public sealed class ShouldExtractFactory(ConfigurationJson configurationJson, IL
|
|||
{
|
||||
private static readonly FrozenDictionary<Type, string> typeSectionNames = GetTypeSectionNames();
|
||||
private static readonly FrozenDictionary<string, Type> sectionNameTypes = GetSectionNameTypes(typeSectionNames);
|
||||
private readonly FrozenDictionary<Type, FrozenSet<string>> resourcesToExtract = GetResourcesToExtract(configurationJson, sectionNameTypes);
|
||||
private readonly FrozenDictionary<Type, FrozenSet<string>> resourcesToExtract = GetResourcesToExtract(configurationJson);
|
||||
private readonly ILogger logger = loggerFactory.CreateLogger<ShouldExtractFactory>();
|
||||
|
||||
private static FrozenDictionary<Type, string> GetTypeSectionNames() =>
|
||||
|
@ -32,22 +35,23 @@ public sealed class ShouldExtractFactory(ConfigurationJson configurationJson, IL
|
|||
[typeof(GroupName)] = "groupNames",
|
||||
[typeof(SubscriptionName)] = "subscriptionNames",
|
||||
[typeof(ApiName)] = "apiNames",
|
||||
[typeof(WorkspaceName)] = "workspaceNames",
|
||||
}
|
||||
.ToFrozenDictionary();
|
||||
|
||||
private static FrozenDictionary<string, Type> GetSectionNameTypes(FrozenDictionary<Type, string> typeSectionNames) =>
|
||||
typeSectionNames.ToFrozenDictionary(kvp => kvp.Value, kvp => kvp.Key, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private static FrozenDictionary<Type, FrozenSet<string>> GetResourcesToExtract(ConfigurationJson configurationJson, FrozenDictionary<string, Type> sectionNameTypes) =>
|
||||
private static FrozenDictionary<Type, FrozenSet<string>> GetResourcesToExtract(ConfigurationJson configurationJson) =>
|
||||
configurationJson.Value
|
||||
// Get configuration sections that are JSON arrays
|
||||
.ChooseValue(node => node.TryAsJsonArray())
|
||||
.ChooseValues(node => node.TryAsJsonArray().ToOption())
|
||||
// Map each JSON array to a set of strings
|
||||
.MapValue(jsonArray => jsonArray.Choose(node => node.TryAsString())
|
||||
.Where(value => string.IsNullOrWhiteSpace(value) is false)
|
||||
.ToFrozenSet(StringComparer.OrdinalIgnoreCase))
|
||||
.Select(kvp => kvp.MapValue(jsonArray => jsonArray.PickStrings()
|
||||
.Where(value => string.IsNullOrWhiteSpace(value) is false)
|
||||
.ToFrozenSet(StringComparer.OrdinalIgnoreCase)))
|
||||
// Map each configuration section to a resource name type
|
||||
.ChooseKey(sectionNameTypes.Find)
|
||||
.ChooseKeys(sectionNameTypes.Find)
|
||||
.ToFrozenDictionary();
|
||||
|
||||
public static string GetConfigurationSectionName<T>() =>
|
||||
|
@ -75,9 +79,27 @@ public sealed class ShouldExtractFactory(ConfigurationJson configurationJson, IL
|
|||
|
||||
if (shouldExtract is false)
|
||||
{
|
||||
logger.LogWarning("{ResourceType} {ResourceName} is not in configuration and will be skipped.", typeof(TName).Name, name);
|
||||
logger.LogWarning("{ResourceType} {ResourceName} is not in configuration and will be not be extracted.", typeof(TName).Name, name);
|
||||
}
|
||||
|
||||
return shouldExtract;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class ShouldExtractModule
|
||||
{
|
||||
public static void ConfigureShouldExtractFactory(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigurationModule.ConfigureConfigurationJson(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractFactory);
|
||||
}
|
||||
|
||||
private static ShouldExtractFactory GetShouldExtractFactory(IServiceProvider provider)
|
||||
{
|
||||
var configurationJson = provider.GetRequiredService<ConfigurationJson>();
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
|
||||
return new ShouldExtractFactory(configurationJson, loggerFactory);
|
||||
}
|
||||
}
|
|
@ -3,122 +3,140 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractSubscriptions(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractSubscriptions(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(SubscriptionName Name, SubscriptionDto Dto)> ListSubscriptions(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractSubscription(SubscriptionName name, SubscriptionDto dto);
|
||||
public delegate ValueTask WriteSubscriptionArtifacts(SubscriptionName name, SubscriptionDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteSubscriptionInformationFile(SubscriptionName name, SubscriptionDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(SubscriptionName Name, SubscriptionDto Dto)> ListSubscriptions(CancellationToken cancellationToken);
|
||||
|
||||
file delegate bool ShouldExtractSubscription(SubscriptionName name, SubscriptionDto dto);
|
||||
|
||||
file delegate ValueTask WriteSubscriptionArtifacts(SubscriptionName name, SubscriptionDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteSubscriptionInformationFile(SubscriptionName name, SubscriptionDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractSubscriptionsHandler(ListSubscriptions list, ShouldExtractSubscription shouldExtractSubscription, WriteSubscriptionArtifacts writeArtifacts)
|
||||
internal static class SubscriptionModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(subscription => shouldExtractSubscription(subscription.Name, subscription.Dto))
|
||||
.IterParallel(async subscription => await writeArtifacts(subscription.Name, subscription.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListSubscriptionsHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(SubscriptionName, SubscriptionDto)> Handle(CancellationToken cancellationToken) =>
|
||||
SubscriptionsUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractSubscriptionHandler(ShouldExtractFactory shouldExtractFactory, ShouldExtractApiName shouldExtractApi, ShouldExtractProduct shouldExtractProduct)
|
||||
{
|
||||
public bool Handle(SubscriptionName name, SubscriptionDto dto) =>
|
||||
// Don't extract the master subscription
|
||||
name != SubscriptionName.From("master")
|
||||
// Check name from configuration override
|
||||
&& shouldExtractFactory.Create<SubscriptionName>().Invoke(name)
|
||||
// Don't extract subscription if its API should not be extracted
|
||||
&& SubscriptionModule.TryGetApiName(dto)
|
||||
.Map(shouldExtractApi.Invoke)
|
||||
.IfNone(true)
|
||||
// Don't extract subscription if its product should not be extracted
|
||||
&& SubscriptionModule.TryGetProductName(dto)
|
||||
.Map(shouldExtractProduct.Invoke)
|
||||
.IfNone(true);
|
||||
|
||||
}
|
||||
|
||||
file sealed class WriteSubscriptionArtifactsHandler(WriteSubscriptionInformationFile writeInformationFile)
|
||||
{
|
||||
public async ValueTask Handle(SubscriptionName name, SubscriptionDto dto, CancellationToken cancellationToken)
|
||||
public static void ConfigureExtractSubscriptions(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
ConfigureListSubscriptions(builder);
|
||||
ConfigureShouldExtractSubscription(builder);
|
||||
ConfigureWriteSubscriptionArtifacts(builder);
|
||||
|
||||
file sealed class WriteSubscriptionInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(SubscriptionName name, SubscriptionDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
var informationFile = SubscriptionInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing subscription information file {InformationFile}", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class SubscriptionServices
|
||||
{
|
||||
public static void ConfigureExtractSubscriptions(IServiceCollection services)
|
||||
{
|
||||
ConfigureListSubscriptions(services);
|
||||
ConfigureShouldExtractSubscription(services);
|
||||
ConfigureWriteSubscriptionArtifacts(services);
|
||||
|
||||
services.TryAddSingleton<ExtractSubscriptionsHandler>();
|
||||
services.TryAddSingleton<ExtractSubscriptions>(provider => provider.GetRequiredService<ExtractSubscriptionsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetExtractSubscriptions);
|
||||
}
|
||||
|
||||
private static void ConfigureListSubscriptions(IServiceCollection services)
|
||||
private static ExtractSubscriptions GetExtractSubscriptions(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListSubscriptionsHandler>();
|
||||
services.TryAddSingleton<ListSubscriptions>(provider => provider.GetRequiredService<ListSubscriptionsHandler>().Handle);
|
||||
var list = provider.GetRequiredService<ListSubscriptions>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractSubscription>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteSubscriptionArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractSubscriptions));
|
||||
|
||||
logger.LogInformation("Extracting subscriptions...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(subscription => shouldExtract(subscription.Name, subscription.Dto))
|
||||
.IterParallel(async subscription => await writeArtifacts(subscription.Name, subscription.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractSubscription(IServiceCollection services)
|
||||
private static void ConfigureListSubscriptions(IHostApplicationBuilder builder)
|
||||
{
|
||||
ApiServices.ConfigureShouldExtractApiName(services);
|
||||
ProductServices.ConfigureShouldExtractProduct(services);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
services.TryAddSingleton<ShouldExtractSubscriptionHandler>();
|
||||
services.TryAddSingleton<ShouldExtractSubscription>(provider => provider.GetRequiredService<ShouldExtractSubscriptionHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetListSubscriptions);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteSubscriptionArtifacts(IServiceCollection services)
|
||||
private static ListSubscriptions GetListSubscriptions(IServiceProvider provider)
|
||||
{
|
||||
ConfigureWriteSubscriptionInformationFile(services);
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
services.TryAddSingleton<WriteSubscriptionArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteSubscriptionArtifacts>(provider => provider.GetRequiredService<WriteSubscriptionArtifactsHandler>().Handle);
|
||||
return cancellationToken =>
|
||||
SubscriptionsUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteSubscriptionInformationFile(IServiceCollection services)
|
||||
private static void ConfigureShouldExtractSubscription(IHostApplicationBuilder builder)
|
||||
{
|
||||
services.TryAddSingleton<WriteSubscriptionInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteSubscriptionInformationFile>(provider => provider.GetRequiredService<WriteSubscriptionInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
ApiModule.ConfigureShouldExtractApiName(builder);
|
||||
ProductModule.ConfigureShouldExtractProduct(builder);
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("SubscriptionExtractor");
|
||||
builder.Services.TryAddSingleton(GetShouldExtractSubscription);
|
||||
}
|
||||
|
||||
private static ShouldExtractSubscription GetShouldExtractSubscription(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
var shouldExtractApi = provider.GetRequiredService<ShouldExtractApiName>();
|
||||
var shouldExtractProduct = provider.GetRequiredService<ShouldExtractProduct>();
|
||||
|
||||
var shouldExtractSubscriptionName = shouldExtractFactory.Create<SubscriptionName>();
|
||||
|
||||
return (name, dto) =>
|
||||
// Don't extract the master subscription
|
||||
name != SubscriptionName.From("master")
|
||||
// Check name from configuration override
|
||||
&& shouldExtractSubscriptionName(name)
|
||||
// Don't extract subscription if its API should not be extracted
|
||||
&& common.SubscriptionModule.TryGetApiName(dto)
|
||||
.Map(shouldExtractApi.Invoke)
|
||||
.IfNone(true)
|
||||
// Don't extract subscription if its product should not be extracted
|
||||
&& common.SubscriptionModule.TryGetProductName(dto)
|
||||
.Map(shouldExtractProduct.Invoke)
|
||||
.IfNone(true);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteSubscriptionArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteSubscriptionInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteSubscriptionArtifacts);
|
||||
}
|
||||
|
||||
private static WriteSubscriptionArtifacts GetWriteSubscriptionArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteSubscriptionInformationFile>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteSubscriptionInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteSubscriptionInformationFile);
|
||||
}
|
||||
|
||||
private static WriteSubscriptionInformationFile GetWriteSubscriptionInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = SubscriptionInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing subscription information file {SubscriptionInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -3,110 +3,122 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractTags(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractTags(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(TagName Name, TagDto Dto)> ListTags(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractTag(TagName name);
|
||||
public delegate ValueTask WriteTagArtifacts(TagName name, TagDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteTagInformationFile(TagName name, TagDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(TagName Name, TagDto Dto)> ListTags(CancellationToken cancellationToken);
|
||||
|
||||
internal delegate bool ShouldExtractTag(TagName name);
|
||||
|
||||
file delegate ValueTask WriteTagArtifacts(TagName name, TagDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteTagInformationFile(TagName name, TagDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractTagsHandler(ListTags list, ShouldExtractTag shouldExtract, WriteTagArtifacts writeArtifacts)
|
||||
internal static class TagModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(tag => shouldExtract(tag.Name))
|
||||
.IterParallel(async tag => await writeArtifacts(tag.Name, tag.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListTagsHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(TagName, TagDto)> Handle(CancellationToken cancellationToken) =>
|
||||
TagsUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractTagHandler(ShouldExtractFactory shouldExtractFactory)
|
||||
{
|
||||
public bool Handle(TagName name)
|
||||
public static void ConfigureExtractTags(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListTags(builder);
|
||||
ConfigureShouldExtractTag(builder);
|
||||
ConfigureWriteTagArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractTags);
|
||||
}
|
||||
|
||||
private static ExtractTags GetExtractTags(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListTags>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractTag>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteTagArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractTags));
|
||||
|
||||
logger.LogInformation("Extracting tags...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(tag => shouldExtract(tag.Name))
|
||||
.IterParallel(async tag => await writeArtifacts(tag.Name, tag.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListTags(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListTags);
|
||||
}
|
||||
|
||||
private static ListTags GetListTags(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
TagsUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractTag(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractTag);
|
||||
}
|
||||
|
||||
private static ShouldExtractTag GetShouldExtractTag(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<TagName>();
|
||||
return shouldExtract(name);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteTagArtifactsHandler(WriteTagInformationFile writeInformationFile)
|
||||
{
|
||||
public async ValueTask Handle(TagName name, TagDto dto, CancellationToken cancellationToken)
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteTagArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
ConfigureWriteTagInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteTagArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteTagInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(TagName name, TagDto dto, CancellationToken cancellationToken)
|
||||
private static WriteTagArtifacts GetWriteTagArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var informationFile = TagInformationFile.From(name, serviceDirectory);
|
||||
var writeInformationFile = provider.GetRequiredService<WriteTagInformationFile>();
|
||||
|
||||
logger.LogInformation("Writing tag information file {InformationFile}", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class TagServices
|
||||
{
|
||||
public static void ConfigureExtractTags(IServiceCollection services)
|
||||
private static void ConfigureWriteTagInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListTags(services);
|
||||
ConfigureShouldExtractTag(services);
|
||||
ConfigureWriteTagArtifacts(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton<ExtractTagsHandler>();
|
||||
services.TryAddSingleton<ExtractTags>(provider => provider.GetRequiredService<ExtractTagsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetWriteTagInformationFile);
|
||||
}
|
||||
|
||||
private static void ConfigureListTags(IServiceCollection services)
|
||||
private static WriteTagInformationFile GetWriteTagInformationFile(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListTagsHandler>();
|
||||
services.TryAddSingleton<ListTags>(provider => provider.GetRequiredService<ListTagsHandler>().Handle);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = TagInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing tag information file {TagInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractTag(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<ShouldExtractTagHandler>();
|
||||
services.TryAddSingleton<ShouldExtractTag>(provider => provider.GetRequiredService<ShouldExtractTagHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteTagArtifacts(IServiceCollection services)
|
||||
{
|
||||
ConfigureWriteTagInformationFile(services);
|
||||
|
||||
services.TryAddSingleton<WriteTagArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteTagArtifacts>(provider => provider.GetRequiredService<WriteTagArtifactsHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteTagInformationFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WriteTagInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteTagInformationFile>(provider => provider.GetRequiredService<WriteTagInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("TagExtractor");
|
||||
}
|
|
@ -3,110 +3,122 @@ using common;
|
|||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
internal delegate ValueTask ExtractVersionSets(CancellationToken cancellationToken);
|
||||
public delegate ValueTask ExtractVersionSets(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(VersionSetName Name, VersionSetDto Dto)> ListVersionSets(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractVersionSet(VersionSetName name);
|
||||
public delegate ValueTask WriteVersionSetArtifacts(VersionSetName name, VersionSetDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteVersionSetInformationFile(VersionSetName name, VersionSetDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate IAsyncEnumerable<(VersionSetName Name, VersionSetDto Dto)> ListVersionSets(CancellationToken cancellationToken);
|
||||
|
||||
internal delegate bool ShouldExtractVersionSet(VersionSetName name);
|
||||
|
||||
file delegate ValueTask WriteVersionSetArtifacts(VersionSetName name, VersionSetDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask WriteVersionSetInformationFile(VersionSetName name, VersionSetDto dto, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class ExtractVersionSetsHandler(ListVersionSets list, ShouldExtractVersionSet shouldExtract, WriteVersionSetArtifacts writeArtifacts)
|
||||
internal static class VersionSetModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken) =>
|
||||
await list(cancellationToken)
|
||||
.Where(versionset => shouldExtract(versionset.Name))
|
||||
.IterParallel(async versionset => await writeArtifacts(versionset.Name, versionset.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ListVersionSetsHandler(ManagementServiceUri serviceUri, HttpPipeline pipeline)
|
||||
{
|
||||
public IAsyncEnumerable<(VersionSetName, VersionSetDto)> Handle(CancellationToken cancellationToken) =>
|
||||
VersionSetsUri.From(serviceUri).List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
file sealed class ShouldExtractVersionSetHandler(ShouldExtractFactory shouldExtractFactory)
|
||||
{
|
||||
public bool Handle(VersionSetName name)
|
||||
public static void ConfigureExtractVersionSets(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListVersionSets(builder);
|
||||
ConfigureShouldExtractVersionSet(builder);
|
||||
ConfigureWriteVersionSetArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractVersionSets);
|
||||
}
|
||||
|
||||
private static ExtractVersionSets GetExtractVersionSets(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListVersionSets>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractVersionSet>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteVersionSetArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractVersionSets));
|
||||
|
||||
logger.LogInformation("Extracting version sets...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(versionset => shouldExtract(versionset.Name))
|
||||
.IterParallel(async versionset => await writeArtifacts(versionset.Name, versionset.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListVersionSets(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListVersionSets);
|
||||
}
|
||||
|
||||
private static ListVersionSets GetListVersionSets(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
VersionSetsUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractVersionSet(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractVersionSet);
|
||||
}
|
||||
|
||||
private static ShouldExtractVersionSet GetShouldExtractVersionSet(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<VersionSetName>();
|
||||
return shouldExtract(name);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteVersionSetArtifactsHandler(WriteVersionSetInformationFile writeInformationFile)
|
||||
{
|
||||
public async ValueTask Handle(VersionSetName name, VersionSetDto dto, CancellationToken cancellationToken)
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteVersionSetArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
ConfigureWriteVersionSetInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteVersionSetArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteVersionSetInformationFileHandler(ILoggerFactory loggerFactory, ManagementServiceDirectory serviceDirectory)
|
||||
{
|
||||
private readonly ILogger logger = Common.GetLogger(loggerFactory);
|
||||
|
||||
public async ValueTask Handle(VersionSetName name, VersionSetDto dto, CancellationToken cancellationToken)
|
||||
private static WriteVersionSetArtifacts GetWriteVersionSetArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var informationFile = VersionSetInformationFile.From(name, serviceDirectory);
|
||||
var writeInformationFile = provider.GetRequiredService<WriteVersionSetInformationFile>();
|
||||
|
||||
logger.LogInformation("Writing version set information file {VersionSetInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
return async (name, dto, cancellationToken) =>
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class VersionSetServices
|
||||
{
|
||||
public static void ConfigureExtractVersionSets(IServiceCollection services)
|
||||
private static void ConfigureWriteVersionSetInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListVersionSets(services);
|
||||
ConfigureShouldExtractVersionSet(services);
|
||||
ConfigureWriteVersionSetArtifacts(services);
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
services.TryAddSingleton<ExtractVersionSetsHandler>();
|
||||
services.TryAddSingleton<ExtractVersionSets>(provider => provider.GetRequiredService<ExtractVersionSetsHandler>().Handle);
|
||||
builder.Services.TryAddSingleton(GetWriteVersionSetInformationFile);
|
||||
}
|
||||
|
||||
private static void ConfigureListVersionSets(IServiceCollection services)
|
||||
private static WriteVersionSetInformationFile GetWriteVersionSetInformationFile(IServiceProvider provider)
|
||||
{
|
||||
services.TryAddSingleton<ListVersionSetsHandler>();
|
||||
services.TryAddSingleton<ListVersionSets>(provider => provider.GetRequiredService<ListVersionSetsHandler>().Handle);
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = VersionSetInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing version set information file {VersionSetInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureShouldExtractVersionSet(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<ShouldExtractVersionSetHandler>();
|
||||
services.TryAddSingleton<ShouldExtractVersionSet>(provider => provider.GetRequiredService<ShouldExtractVersionSetHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteVersionSetArtifacts(IServiceCollection services)
|
||||
{
|
||||
ConfigureWriteVersionSetInformationFile(services);
|
||||
|
||||
services.TryAddSingleton<WriteVersionSetArtifactsHandler>();
|
||||
services.TryAddSingleton<WriteVersionSetArtifacts>(provider => provider.GetRequiredService<WriteVersionSetArtifactsHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteVersionSetInformationFile(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WriteVersionSetInformationFileHandler>();
|
||||
services.TryAddSingleton<WriteVersionSetInformationFile>(provider => provider.GetRequiredService<WriteVersionSetInformationFileHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
file static class Common
|
||||
{
|
||||
public static ILogger GetLogger(ILoggerFactory loggerFactory) =>
|
||||
loggerFactory.CreateLogger("VersionSetExtractor");
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaces(CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(WorkspaceName Name, WorkspaceDto Dto)> ListWorkspaces(CancellationToken cancellationToken);
|
||||
public delegate bool ShouldExtractWorkspace(WorkspaceName name);
|
||||
public delegate ValueTask WriteWorkspaceArtifacts(WorkspaceName name, WorkspaceDto dto, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceInformationFile(WorkspaceName name, WorkspaceDto dto, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaces(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaces(builder);
|
||||
ConfigureShouldExtractWorkspace(builder);
|
||||
ConfigureWriteWorkspaceArtifacts(builder);
|
||||
WorkspaceNamedValueModule.ConfigureExtractWorkspaceNamedValues(builder);
|
||||
WorkspaceBackendModule.ConfigureExtractWorkspaceBackends(builder);
|
||||
WorkspaceTagModule.ConfigureExtractWorkspaceTags(builder);
|
||||
WorkspaceVersionSetModule.ConfigureExtractWorkspaceVersionSets(builder);
|
||||
WorkspaceLoggerModule.ConfigureExtractWorkspaceLoggers(builder);
|
||||
WorkspaceDiagnosticModule.ConfigureExtractWorkspaceDiagnostics(builder);
|
||||
WorkspacePolicyFragmentModule.ConfigureExtractWorkspacePolicyFragments(builder);
|
||||
WorkspacePolicyModule.ConfigureExtractWorkspacePolicies(builder);
|
||||
WorkspaceProductModule.ConfigureExtractWorkspaceProducts(builder);
|
||||
WorkspaceGroupModule.ConfigureExtractWorkspaceGroups(builder);
|
||||
WorkspaceApiModule.ConfigureExtractWorkspaceApis(builder);
|
||||
WorkspaceSubscriptionModule.ConfigureExtractWorkspaceSubscriptions(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaces);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaces GetExtractWorkspaces(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaces>();
|
||||
var shouldExtract = provider.GetRequiredService<ShouldExtractWorkspace>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceArtifacts>();
|
||||
var extractWorkspaceNamedValues = provider.GetRequiredService<ExtractWorkspaceNamedValues>();
|
||||
var extractWorkspaceBackends = provider.GetRequiredService<ExtractWorkspaceBackends>();
|
||||
var extractWorkspaceTags = provider.GetRequiredService<ExtractWorkspaceTags>();
|
||||
var extractWorkspaceVersionSets = provider.GetRequiredService<ExtractWorkspaceVersionSets>();
|
||||
var extractWorkspaceLoggers = provider.GetRequiredService<ExtractWorkspaceLoggers>();
|
||||
var extractWorkspaceDiagnostics = provider.GetRequiredService<ExtractWorkspaceDiagnostics>();
|
||||
var extractWorkspacePolicyFragments = provider.GetRequiredService<ExtractWorkspacePolicyFragments>();
|
||||
var extractWorkspacePolicies = provider.GetRequiredService<ExtractWorkspacePolicies>();
|
||||
var extractWorkspaceProducts = provider.GetRequiredService<ExtractWorkspaceProducts>();
|
||||
var extractWorkspaceGroups = provider.GetRequiredService<ExtractWorkspaceGroups>();
|
||||
var extractWorkspaceApis = provider.GetRequiredService<ExtractWorkspaceApis>();
|
||||
var extractWorkspaceSubscriptions = provider.GetRequiredService<ExtractWorkspaceSubscriptions>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaces));
|
||||
|
||||
logger.LogInformation("Extracting workspaces...");
|
||||
|
||||
await list(cancellationToken)
|
||||
.Where(workspace => shouldExtract(workspace.Name))
|
||||
.IterParallel(async workspace => await extractWorkspace(workspace.Name, workspace.Dto, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
|
||||
async ValueTask extractWorkspace(WorkspaceName name, WorkspaceDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
//await writeArtifacts(name, dto, cancellationToken); // TODO: Revisit support for writing workspace artifacts
|
||||
await extractWorkspaceNamedValues(name, cancellationToken);
|
||||
await extractWorkspaceBackends(name, cancellationToken);
|
||||
await extractWorkspaceTags(name, cancellationToken);
|
||||
await extractWorkspaceVersionSets(name, cancellationToken);
|
||||
await extractWorkspaceLoggers(name, cancellationToken);
|
||||
await extractWorkspaceDiagnostics(name, cancellationToken);
|
||||
await extractWorkspacePolicyFragments(name, cancellationToken);
|
||||
await extractWorkspacePolicies(name, cancellationToken);
|
||||
await extractWorkspaceProducts(name, cancellationToken);
|
||||
await extractWorkspaceGroups(name, cancellationToken);
|
||||
await extractWorkspaceApis(name, cancellationToken);
|
||||
await extractWorkspaceSubscriptions(name, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaces(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaces);
|
||||
}
|
||||
|
||||
private static ListWorkspaces GetListWorkspaces(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return cancellationToken =>
|
||||
WorkspacesUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureShouldExtractWorkspace(IHostApplicationBuilder builder)
|
||||
{
|
||||
ShouldExtractModule.ConfigureShouldExtractFactory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetShouldExtractWorkspace);
|
||||
}
|
||||
|
||||
private static ShouldExtractWorkspace GetShouldExtractWorkspace(IServiceProvider provider)
|
||||
{
|
||||
var shouldExtractFactory = provider.GetRequiredService<ShouldExtractFactory>();
|
||||
|
||||
var shouldExtract = shouldExtractFactory.Create<WorkspaceName>();
|
||||
|
||||
return name => shouldExtract(name);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceArtifacts GetWriteWorkspaceArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceInformationFile>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
await writeInformationFile(name, dto, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceInformationFile GetWriteWorkspaceInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceInformationFile.From(name, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace information file {WorkspaceInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using LanguageExt;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceApis(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ApiName Name, WorkspaceApiDto Dto, Option<(ApiSpecification Specification, BinaryData Contents)> SpecificationOption)> ListWorkspaceApis(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceApiArtifacts(ApiName name, WorkspaceApiDto dto, Option<(ApiSpecification Specification, BinaryData Contents)> specificationOption, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceApiInformationFile(ApiName name, WorkspaceApiDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceApiSpecificationFile(ApiName name, ApiSpecification specification, BinaryData contents, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceApiModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceApis(builder);
|
||||
ConfigureWriteWorkspaceApiArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceApis);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceApis GetExtractWorkspaceApis(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceApis>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceApiArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceApis));
|
||||
|
||||
logger.LogInformation("Extracting APIs for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
// Group APIs by version set (https://github.com/Azure/apiops/issues/316).
|
||||
// We'll process each group in parallel, but each API within a group sequentially.
|
||||
.GroupBy(api => api.Dto.Properties.ApiVersionSetId ?? string.Empty)
|
||||
.IterParallel(async group => await group.Iter(async api => await extractApi(api.Name, api.Dto, api.SpecificationOption, workspaceName, cancellationToken),
|
||||
cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
|
||||
async ValueTask extractApi(ApiName name, WorkspaceApiDto dto, Option<(ApiSpecification Specification, BinaryData Contents)> specificationOption, WorkspaceName workspaceName, CancellationToken cancellationToken)
|
||||
{
|
||||
await writeArtifacts(name, dto, specificationOption, workspaceName, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
ApiSpecificationModule.ConfigureDefaultApiSpecification(builder);
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceApis);
|
||||
}
|
||||
|
||||
private static ListWorkspaceApis GetListWorkspaceApis(IServiceProvider provider)
|
||||
{
|
||||
var defaultApiSpecification = provider.GetRequiredService<DefaultApiSpecification>();
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
{
|
||||
var workspaceApisUri = WorkspaceApisUri.From(workspaceName, serviceUri);
|
||||
|
||||
return workspaceApisUri.List(pipeline, cancellationToken)
|
||||
.SelectAwait(async api =>
|
||||
{
|
||||
var (name, dto) = api;
|
||||
var specificationContentsOption = await tryGetSpecificationContents(name, dto, workspaceName, cancellationToken);
|
||||
return (name, dto, specificationContentsOption);
|
||||
});
|
||||
};
|
||||
|
||||
async ValueTask<Option<(ApiSpecification, BinaryData)>> tryGetSpecificationContents(ApiName name, WorkspaceApiDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken)
|
||||
{
|
||||
var specificationOption = tryGetSpecification(dto);
|
||||
|
||||
return await specificationOption.BindTask(async specification =>
|
||||
{
|
||||
var uri = WorkspaceApiUri.From(name, workspaceName, serviceUri);
|
||||
var contentsOption = await uri.TryGetSpecificationContents(specification, pipeline, cancellationToken);
|
||||
|
||||
return from contents in contentsOption
|
||||
select (specification, contents);
|
||||
});
|
||||
}
|
||||
|
||||
Option<ApiSpecification> tryGetSpecification(WorkspaceApiDto dto) =>
|
||||
(dto.Properties.Type ?? dto.Properties.ApiType) switch
|
||||
{
|
||||
"graphql" => new ApiSpecification.GraphQl(),
|
||||
"soap" => new ApiSpecification.Wsdl(),
|
||||
"http" => defaultApiSpecification.Value,
|
||||
null => defaultApiSpecification.Value,
|
||||
_ => Option<ApiSpecification>.None
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceApiArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceApiInformationFile(builder);
|
||||
ConfigureWriteWorkspaceApiSpecificationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceApiArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceApiArtifacts GetWriteWorkspaceApiArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceApiInformationFile>();
|
||||
var writeSpecificationFile = provider.GetRequiredService<WriteWorkspaceApiSpecificationFile>();
|
||||
|
||||
return async (name, dto, specificationContentsOption, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
|
||||
await specificationContentsOption.IterTask(async x =>
|
||||
{
|
||||
var (specification, contents) = x;
|
||||
await writeSpecificationFile(name, specification, contents, workspaceName, cancellationToken);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceApiInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceApiInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceApiInformationFile GetWriteWorkspaceApiInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceApiInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace API information file {WorkspaceApiInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceApiSpecificationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceApiSpecificationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceApiSpecificationFile GetWriteWorkspaceApiSpecificationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, specification, contents, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var specificationFile = WorkspaceApiSpecificationFile.From(specification, name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace API specification file {WorkspaceApiSpecificationFile}...", specificationFile);
|
||||
await specificationFile.WriteSpecification(contents, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceBackends(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(BackendName Name, WorkspaceBackendDto Dto)> ListWorkspaceBackends(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceBackendArtifacts(BackendName name, WorkspaceBackendDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceBackendInformationFile(BackendName name, WorkspaceBackendDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceBackendModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceBackends(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceBackends(builder);
|
||||
ConfigureWriteWorkspaceBackendArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceBackends);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceBackends GetExtractWorkspaceBackends(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceBackends>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceBackendArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceBackends));
|
||||
|
||||
logger.LogInformation("Extracting backends for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async resource => await writeArtifacts(resource.Name, resource.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceBackends(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceBackends);
|
||||
}
|
||||
|
||||
private static ListWorkspaceBackends GetListWorkspaceBackends(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
{
|
||||
var workspaceBackendsUri = WorkspaceBackendsUri.From(workspaceName, serviceUri);
|
||||
return workspaceBackendsUri.List(pipeline, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceBackendArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceBackendInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceBackendArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceBackendArtifacts GetWriteWorkspaceBackendArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceBackendInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceBackendInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceBackendInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceBackendInformationFile GetWriteWorkspaceBackendInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceBackendInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace backend information file {WorkspaceBackendInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceDiagnostics(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(DiagnosticName Name, WorkspaceDiagnosticDto Dto)> ListWorkspaceDiagnostics(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceDiagnosticArtifacts(DiagnosticName name, WorkspaceDiagnosticDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceDiagnosticInformationFile(DiagnosticName name, WorkspaceDiagnosticDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceDiagnosticModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceDiagnostics(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceDiagnostics(builder);
|
||||
ConfigureWriteWorkspaceDiagnosticArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceDiagnostics);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceDiagnostics GetExtractWorkspaceDiagnostics(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceDiagnostics>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceDiagnosticArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceDiagnostics));
|
||||
|
||||
logger.LogInformation("Extracting diagnostics for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async diagnostic => await writeArtifacts(diagnostic.Name, diagnostic.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceDiagnostics(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceDiagnostics);
|
||||
}
|
||||
|
||||
private static ListWorkspaceDiagnostics GetListWorkspaceDiagnostics(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspaceDiagnosticsUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceDiagnosticArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceDiagnosticInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceDiagnosticArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceDiagnosticArtifacts GetWriteWorkspaceDiagnosticArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceDiagnosticInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceDiagnosticInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceDiagnosticInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceDiagnosticInformationFile GetWriteWorkspaceDiagnosticInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceDiagnosticInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace diagnostic information file {WorkspaceDiagnosticInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceGroups(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(GroupName Name, WorkspaceGroupDto Dto)> ListWorkspaceGroups(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceGroupArtifacts(GroupName name, WorkspaceGroupDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceGroupInformationFile(GroupName name, WorkspaceGroupDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceGroupModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceGroups(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceGroups(builder);
|
||||
ConfigureWriteWorkspaceGroupArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceGroups);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceGroups GetExtractWorkspaceGroups(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceGroups>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceGroupArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceGroups));
|
||||
|
||||
logger.LogInformation("Extracting groups for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async group => await writeArtifacts(group.Name, group.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceGroups(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceGroups);
|
||||
}
|
||||
|
||||
private static ListWorkspaceGroups GetListWorkspaceGroups(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspaceGroupsUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceGroupArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceGroupInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceGroupArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceGroupArtifacts GetWriteWorkspaceGroupArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceGroupInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceGroupInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceGroupInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceGroupInformationFile GetWriteWorkspaceGroupInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceGroupInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace group information file {WorkspaceGroupInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceLoggers(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(LoggerName Name, WorkspaceLoggerDto Dto)> ListWorkspaceLoggers(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceLoggerArtifacts(LoggerName name, WorkspaceLoggerDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceLoggerInformationFile(LoggerName name, WorkspaceLoggerDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceLoggerModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceLoggers(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceLoggers(builder);
|
||||
ConfigureWriteWorkspaceLoggerArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceLoggers);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceLoggers GetExtractWorkspaceLoggers(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceLoggers>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceLoggerArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceLoggers));
|
||||
|
||||
logger.LogInformation("Extracting loggers for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async logger => await writeArtifacts(logger.Name, logger.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceLoggers(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceLoggers);
|
||||
}
|
||||
|
||||
private static ListWorkspaceLoggers GetListWorkspaceLoggers(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspaceLoggersUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceLoggerArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceLoggerInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceLoggerArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceLoggerArtifacts GetWriteWorkspaceLoggerArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceLoggerInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceLoggerInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceLoggerInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceLoggerInformationFile GetWriteWorkspaceLoggerInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceLoggerInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace logger information file {WorkspaceLoggerInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceNamedValues(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(NamedValueName Name, WorkspaceNamedValueDto Dto)> ListWorkspaceNamedValues(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceNamedValueArtifacts(NamedValueName name, WorkspaceNamedValueDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceNamedValueInformationFile(NamedValueName name, WorkspaceNamedValueDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceNamedValueModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceNamedValues(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceNamedValues(builder);
|
||||
ConfigureWriteWorkspaceNamedValueArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceNamedValues);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceNamedValues GetExtractWorkspaceNamedValues(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceNamedValues>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceNamedValueArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceNamedValues));
|
||||
|
||||
logger.LogInformation("Extracting named values for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async namedValue => await writeArtifacts(namedValue.Name, namedValue.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceNamedValues(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceNamedValues);
|
||||
}
|
||||
|
||||
private static ListWorkspaceNamedValues GetListWorkspaceNamedValues(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspaceNamedValuesUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceNamedValueArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceNamedValueInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceNamedValueArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceNamedValueArtifacts GetWriteWorkspaceNamedValueArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceNamedValueInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceNamedValueInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceNamedValueInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceNamedValueInformationFile GetWriteWorkspaceNamedValueInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceNamedValueInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace named value information file {WorkspaceNamedValueInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspacePolicies(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(WorkspacePolicyName Name, WorkspacePolicyDto Dto)> ListWorkspacePolicies(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspacePolicyArtifacts(WorkspacePolicyName name, WorkspacePolicyDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspacePolicyFile(WorkspacePolicyName name, WorkspacePolicyDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspacePolicyModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspacePolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspacePolicies(builder);
|
||||
ConfigureWriteWorkspacePolicyArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspacePolicies);
|
||||
}
|
||||
|
||||
private static ExtractWorkspacePolicies GetExtractWorkspacePolicies(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspacePolicies>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspacePolicyArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspacePolicies));
|
||||
|
||||
logger.LogInformation("Extracting policies for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async policy => await writeArtifacts(policy.Name, policy.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspacePolicies(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspacePolicies);
|
||||
}
|
||||
|
||||
private static ListWorkspacePolicies GetListWorkspacePolicies(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspacePoliciesUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspacePolicyArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspacePolicyFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspacePolicyArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspacePolicyArtifacts GetWriteWorkspacePolicyArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writePolicyFile = provider.GetRequiredService<WriteWorkspacePolicyFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
await writePolicyFile(name, dto, workspaceName, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspacePolicyFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspacePolicyFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspacePolicyFile GetWriteWorkspacePolicyFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var policyFile = WorkspacePolicyFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace policy file {PolicyFile}", policyFile);
|
||||
var policy = dto.Properties.Value ?? string.Empty;
|
||||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspacePolicyFragments(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(PolicyFragmentName Name, WorkspacePolicyFragmentDto Dto)> ListWorkspacePolicyFragments(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspacePolicyFragmentArtifacts(PolicyFragmentName name, WorkspacePolicyFragmentDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspacePolicyFragmentInformationFile(PolicyFragmentName name, WorkspacePolicyFragmentDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspacePolicyFragmentPolicyFile(PolicyFragmentName name, WorkspacePolicyFragmentDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspacePolicyFragmentModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspacePolicyFragments(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspacePolicyFragments(builder);
|
||||
ConfigureWriteWorkspacePolicyFragmentArtifacts(builder);
|
||||
ConfigureWriteWorkspacePolicyFragmentArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspacePolicyFragments);
|
||||
}
|
||||
|
||||
private static ExtractWorkspacePolicyFragments GetExtractWorkspacePolicyFragments(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspacePolicyFragments>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspacePolicyFragmentArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspacePolicyFragments));
|
||||
|
||||
logger.LogInformation("Extracting policy fragments for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async policyFragment => await writeArtifacts(policyFragment.Name, policyFragment.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspacePolicyFragments(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspacePolicyFragments);
|
||||
}
|
||||
|
||||
private static ListWorkspacePolicyFragments GetListWorkspacePolicyFragments(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspacePolicyFragmentsUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspacePolicyFragmentArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspacePolicyFragmentInformationFile(builder);
|
||||
ConfigureWriteWorkspacePolicyFragmentPolicyFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspacePolicyFragmentArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspacePolicyFragmentArtifacts GetWriteWorkspacePolicyFragmentArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspacePolicyFragmentInformationFile>();
|
||||
var writePolicyFile = provider.GetRequiredService<WriteWorkspacePolicyFragmentPolicyFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
await writePolicyFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspacePolicyFragmentInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspacePolicyFragmentInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspacePolicyFragmentInformationFile GetWriteWorkspacePolicyFragmentInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspacePolicyFragmentInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace policy fragment information file {WorkspacePolicyFragmentInformationFile}...", informationFile);
|
||||
|
||||
// Remove policy contents from DTO, as these will be written to the policy file
|
||||
var updatedDto = dto with { Properties = dto.Properties with { Format = null, Value = null } };
|
||||
await informationFile.WriteDto(updatedDto, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspacePolicyFragmentPolicyFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspacePolicyFragmentPolicyFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspacePolicyFragmentPolicyFile GetWriteWorkspacePolicyFragmentPolicyFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var policyFile = WorkspacePolicyFragmentPolicyFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace policy fragment policy file {WorkspacePolicyFragmentPolicyFile}...", policyFile);
|
||||
var policy = dto.Properties.Value ?? string.Empty;
|
||||
await policyFile.WritePolicy(policy, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceProducts(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(ProductName Name, WorkspaceProductDto Dto)> ListWorkspaceProducts(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceProductArtifacts(ProductName name, WorkspaceProductDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceProductInformationFile(ProductName name, WorkspaceProductDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceProductModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceProducts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceProducts(builder);
|
||||
ConfigureWriteWorkspaceProductArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceProducts);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceProducts GetExtractWorkspaceProducts(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceProducts>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceProductArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceProducts));
|
||||
|
||||
logger.LogInformation("Extracting products for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async product => await writeArtifacts(product.Name, product.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceProducts(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceProducts);
|
||||
}
|
||||
|
||||
private static ListWorkspaceProducts GetListWorkspaceProducts(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspaceProductsUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceProductArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceProductInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceProductArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceProductArtifacts GetWriteWorkspaceProductArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceProductInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceProductInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceProductInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceProductInformationFile GetWriteWorkspaceProductInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceProductInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace product information file {WorkspaceProductInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceSubscriptions(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(SubscriptionName Name, WorkspaceSubscriptionDto Dto)> ListWorkspaceSubscriptions(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceSubscriptionArtifacts(SubscriptionName name, WorkspaceSubscriptionDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceSubscriptionInformationFile(SubscriptionName name, WorkspaceSubscriptionDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceSubscriptionModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceSubscriptions(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceSubscriptions(builder);
|
||||
ConfigureWriteWorkspaceSubscriptionArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceSubscriptions);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceSubscriptions GetExtractWorkspaceSubscriptions(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceSubscriptions>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceSubscriptionArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceSubscriptions));
|
||||
|
||||
logger.LogInformation("Extracting subscriptions for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async subscription => await writeArtifacts(subscription.Name, subscription.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceSubscriptions(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceSubscriptions);
|
||||
}
|
||||
|
||||
private static ListWorkspaceSubscriptions GetListWorkspaceSubscriptions(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspaceSubscriptionsUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceSubscriptionArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceSubscriptionInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceSubscriptionArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceSubscriptionArtifacts GetWriteWorkspaceSubscriptionArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceSubscriptionInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceSubscriptionInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceSubscriptionInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceSubscriptionInformationFile GetWriteWorkspaceSubscriptionInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceSubscriptionInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace subscription information file {WorkspaceSubscriptionInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceTags(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(TagName Name, WorkspaceTagDto Dto)> ListWorkspaceTags(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceTagArtifacts(TagName name, WorkspaceTagDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceTagInformationFile(TagName name, WorkspaceTagDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceTagModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceTags(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceTags(builder);
|
||||
ConfigureWriteWorkspaceTagArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceTags);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceTags GetExtractWorkspaceTags(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceTags>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceTagArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceTags));
|
||||
|
||||
logger.LogInformation("Extracting tags for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async tag => await writeArtifacts(tag.Name, tag.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceTags(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceTags);
|
||||
}
|
||||
|
||||
private static ListWorkspaceTags GetListWorkspaceTags(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspaceTagsUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceTagArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceTagInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceTagArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceTagArtifacts GetWriteWorkspaceTagArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceTagInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceTagInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceTagInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceTagInformationFile GetWriteWorkspaceTagInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceTagInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace tag information file {WorkspaceTagInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using Azure.Core.Pipeline;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace extractor;
|
||||
|
||||
public delegate ValueTask ExtractWorkspaceVersionSets(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate IAsyncEnumerable<(VersionSetName Name, WorkspaceVersionSetDto Dto)> ListWorkspaceVersionSets(WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceVersionSetArtifacts(VersionSetName name, WorkspaceVersionSetDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteWorkspaceVersionSetInformationFile(VersionSetName name, WorkspaceVersionSetDto dto, WorkspaceName workspaceName, CancellationToken cancellationToken);
|
||||
|
||||
internal static class WorkspaceVersionSetModule
|
||||
{
|
||||
public static void ConfigureExtractWorkspaceVersionSets(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureListWorkspaceVersionSets(builder);
|
||||
ConfigureWriteWorkspaceVersionSetArtifacts(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetExtractWorkspaceVersionSets);
|
||||
}
|
||||
|
||||
private static ExtractWorkspaceVersionSets GetExtractWorkspaceVersionSets(IServiceProvider provider)
|
||||
{
|
||||
var list = provider.GetRequiredService<ListWorkspaceVersionSets>();
|
||||
var writeArtifacts = provider.GetRequiredService<WriteWorkspaceVersionSetArtifacts>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (workspaceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ExtractWorkspaceVersionSets));
|
||||
|
||||
logger.LogInformation("Extracting version sets for workspace {WorkspaceName}...", workspaceName);
|
||||
|
||||
await list(workspaceName, cancellationToken)
|
||||
.IterParallel(async versionSet => await writeArtifacts(versionSet.Name, versionSet.Dto, workspaceName, cancellationToken),
|
||||
cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureListWorkspaceVersionSets(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetListWorkspaceVersionSets);
|
||||
}
|
||||
|
||||
private static ListWorkspaceVersionSets GetListWorkspaceVersionSets(IServiceProvider provider)
|
||||
{
|
||||
var serviceUri = provider.GetRequiredService<ManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
|
||||
return (workspaceName, cancellationToken) =>
|
||||
WorkspaceVersionSetsUri.From(workspaceName, serviceUri)
|
||||
.List(pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceVersionSetArtifacts(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureWriteWorkspaceVersionSetInformationFile(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceVersionSetArtifacts);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceVersionSetArtifacts GetWriteWorkspaceVersionSetArtifacts(IServiceProvider provider)
|
||||
{
|
||||
var writeInformationFile = provider.GetRequiredService<WriteWorkspaceVersionSetInformationFile>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
await writeInformationFile(name, dto, workspaceName, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
private static void ConfigureWriteWorkspaceVersionSetInformationFile(IHostApplicationBuilder builder)
|
||||
{
|
||||
AzureModule.ConfigureManagementServiceDirectory(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetWriteWorkspaceVersionSetInformationFile);
|
||||
}
|
||||
|
||||
private static WriteWorkspaceVersionSetInformationFile GetWriteWorkspaceVersionSetInformationFile(IServiceProvider provider)
|
||||
{
|
||||
var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, dto, workspaceName, cancellationToken) =>
|
||||
{
|
||||
var informationFile = WorkspaceVersionSetInformationFile.From(name, workspaceName, serviceDirectory);
|
||||
|
||||
logger.LogInformation("Writing workspace version set information file {WorkspaceVersionSetInformationFile}...", informationFile);
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AnalysisLevel>8-all</AnalysisLevel>
|
||||
<WarningsNotAsErrors>CA1708,CA1724,CA1812,CA1848,CA2007,CA1034,CA1062</WarningsNotAsErrors>
|
||||
|
@ -13,8 +12,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.FeatureManagement" Version="3.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -8,12 +8,12 @@ using LanguageExt;
|
|||
using LanguageExt.UnsafeValueAccess;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using publisher;
|
||||
using System;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
@ -21,496 +21,526 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace integration.tests;
|
||||
|
||||
internal delegate ValueTask DeleteAllApis(ManagementServiceName serviceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask DeleteAllApis(ManagementServiceName serviceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask PutApiModels(IEnumerable<ApiModel> models, ManagementServiceName serviceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ValidateExtractedApis(Option<FrozenSet<ApiName>> apiNamesOption, Option<ApiSpecification> defaultApiSpecification, Option<FrozenSet<VersionSetName>> versionSetNamesOption, ManagementServiceName serviceName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken);
|
||||
public delegate ValueTask<FrozenDictionary<ApiName, ApiDto>> GetApimApis(ManagementServiceName serviceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask<Option<BinaryData>> TryGetApimGraphQlSchema(ApiName name, ManagementServiceName serviceName, CancellationToken cancellationToken);
|
||||
public delegate ValueTask<FrozenDictionary<ApiName, ApiDto>> GetFileApis(ManagementServiceDirectory serviceDirectory, Option<CommitId> commitIdOption, CancellationToken cancellationToken);
|
||||
public delegate ValueTask WriteApiModels(IEnumerable<ApiModel> models, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken);
|
||||
public delegate ValueTask ValidatePublishedApis(IDictionary<ApiName, ApiDto> overrides, Option<CommitId> commitIdOption, ManagementServiceName serviceName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask PutApiModels(IEnumerable<ApiModel> models, ManagementServiceName serviceName, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask ValidateExtractedApis(Option<FrozenSet<ApiName>> apiNamesOption, Option<ApiSpecification> defaultApiSpecification, Option<FrozenSet<VersionSetName>> versionSetNamesOption, ManagementServiceName serviceName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask<FrozenDictionary<ApiName, ApiDto>> GetApimApis(ManagementServiceName serviceName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask<Option<BinaryData>> TryGetApimGraphQlSchema(ApiName name, ManagementServiceName serviceName, CancellationToken cancellationToken);
|
||||
|
||||
file delegate ValueTask<FrozenDictionary<ApiName, ApiDto>> GetFileApis(ManagementServiceDirectory serviceDirectory, Option<CommitId> commitIdOption, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask WriteApiModels(IEnumerable<ApiModel> models, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken);
|
||||
|
||||
internal delegate ValueTask ValidatePublishedApis(IDictionary<ApiName, ApiDto> overrides, Option<CommitId> commitIdOption, ManagementServiceName serviceName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken);
|
||||
|
||||
file sealed class DeleteAllApisHandler(ILogger<DeleteAllApis> logger, GetManagementServiceUri getServiceUri, HttpPipeline pipeline, ActivitySource activitySource)
|
||||
public static class ApiModule
|
||||
{
|
||||
public async ValueTask Handle(ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
public static void ConfigureDeleteAllApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(DeleteAllApis));
|
||||
ManagementServiceModule.ConfigureGetManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
logger.LogInformation("Deleting all APIs in {ServiceName}...", serviceName);
|
||||
var serviceUri = getServiceUri(serviceName);
|
||||
await ApisUri.From(serviceUri).DeleteAll(pipeline, cancellationToken);
|
||||
builder.Services.TryAddSingleton(GetDeleteAllApis);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class PutApiModelsHandler(ILogger<PutApiModels> logger, GetManagementServiceUri getServiceUri, HttpPipeline pipeline, ActivitySource activitySource)
|
||||
{
|
||||
public async ValueTask Handle(IEnumerable<ApiModel> models, ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
private static DeleteAllApis GetDeleteAllApis(IServiceProvider provider)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(PutApiModels));
|
||||
var getServiceUri = provider.GetRequiredService<GetManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
logger.LogInformation("Putting API models in {ServiceName}...", serviceName);
|
||||
await models.IterParallel(async model =>
|
||||
return async (serviceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(DeleteAllApis));
|
||||
|
||||
logger.LogInformation("Deleting all APIs in {ServiceName}...", serviceName);
|
||||
|
||||
var serviceUri = getServiceUri(serviceName);
|
||||
async ValueTask putRevision(ApiRevision revision) => await Put(model.Name, model.Type, model.Path, model.Version, revision, serviceUri, cancellationToken);
|
||||
|
||||
// Put first revision to make sure it's the current revision.
|
||||
await model.Revisions.HeadOrNone().IterTask(putRevision);
|
||||
|
||||
// Put other revisions
|
||||
await model.Revisions.Skip(1).IterParallel(putRevision, cancellationToken);
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
private async ValueTask Put(ApiName name, ApiType type, string path, Option<ApiVersion> version, ApiRevision revision, ManagementServiceUri serviceUri, CancellationToken cancellationToken)
|
||||
{
|
||||
var rootName = ApiName.GetRootName(name);
|
||||
var dto = GetDto(rootName, type, path, version, revision);
|
||||
var revisionedName = ApiName.GetRevisionedName(rootName, revision.Number);
|
||||
|
||||
var uri = ApiUri.From(revisionedName, serviceUri);
|
||||
await uri.PutDto(dto, pipeline, cancellationToken);
|
||||
|
||||
if (type is ApiType.GraphQl)
|
||||
{
|
||||
await revision.Specification.IterTask(async specification => await uri.PutGraphQlSchema(specification, pipeline, cancellationToken));
|
||||
}
|
||||
|
||||
await ApiPolicy.Put(revision.Policies, revisionedName, serviceUri, pipeline, cancellationToken);
|
||||
await ApiTag.Put(revision.Tags, revisionedName, serviceUri, pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
private static ApiDto GetDto(ApiName name, ApiType type, string path, Option<ApiVersion> version, ApiRevision revision) =>
|
||||
new ApiDto()
|
||||
{
|
||||
Properties = new ApiDto.ApiCreateOrUpdateProperties
|
||||
{
|
||||
// APIM sets the description to null when it imports for SOAP APIs.
|
||||
DisplayName = name.ToString(),
|
||||
Path = path,
|
||||
ApiType = type switch
|
||||
{
|
||||
ApiType.Http => null,
|
||||
ApiType.Soap => "soap",
|
||||
ApiType.GraphQl => null,
|
||||
ApiType.WebSocket => null,
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
Type = type switch
|
||||
{
|
||||
ApiType.Http => "http",
|
||||
ApiType.Soap => "soap",
|
||||
ApiType.GraphQl => "graphql",
|
||||
ApiType.WebSocket => "websocket",
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
Protocols = type switch
|
||||
{
|
||||
ApiType.Http => ["http", "https"],
|
||||
ApiType.Soap => ["http", "https"],
|
||||
ApiType.GraphQl => ["http", "https"],
|
||||
ApiType.WebSocket => ["ws", "wss"],
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
ServiceUrl = revision.ServiceUri.ValueUnsafe()?.ToString(),
|
||||
ApiRevisionDescription = revision.Description.ValueUnsafe(),
|
||||
ApiRevision = $"{revision.Number.ToInt()}",
|
||||
ApiVersion = version.Map(version => version.Version).ValueUnsafe(),
|
||||
ApiVersionSetId = version.Map(version => $"/apiVersionSets/{version.VersionSetName}").ValueUnsafe()
|
||||
}
|
||||
await ApisUri.From(serviceUri)
|
||||
.DeleteAll(pipeline, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
file sealed class ValidateExtractedApisHandler(ILogger<ValidateExtractedApis> logger, GetApimApis getApimResources, TryGetApimGraphQlSchema tryGetApimGraphQlSchema, GetFileApis getFileResources, ActivitySource activitySource)
|
||||
{
|
||||
public async ValueTask Handle(Option<FrozenSet<ApiName>> apiNamesOption, Option<ApiSpecification> defaultApiSpecification, Option<FrozenSet<VersionSetName>> versionSetNamesOption, ManagementServiceName serviceName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ValidateExtractedApis));
|
||||
|
||||
logger.LogInformation("Validating extracted APIs in {ServiceName}...", serviceName);
|
||||
|
||||
var expected = await GetExpectedResources(apiNamesOption, versionSetNamesOption, serviceName, cancellationToken);
|
||||
|
||||
await ValidateExtractedInformationFiles(expected, serviceDirectory, cancellationToken);
|
||||
await ValidateExtractedSpecificationFiles(expected, defaultApiSpecification, serviceName, serviceDirectory, cancellationToken);
|
||||
}
|
||||
|
||||
private async ValueTask<ImmutableDictionary<ApiName, ApiDto>> GetExpectedResources(Option<FrozenSet<ApiName>> apiNamesOption, Option<FrozenSet<VersionSetName>> versionSetNamesOption, ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
public static void ConfigurePutApiModels(IHostApplicationBuilder builder)
|
||||
{
|
||||
var apimResources = await getApimResources(serviceName, cancellationToken);
|
||||
ManagementServiceModule.ConfigureGetManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
return apimResources.WhereKey(name => ExtractorOptions.ShouldExtract(name, apiNamesOption))
|
||||
.WhereValue(dto => ApiModule.TryGetVersionSetName(dto)
|
||||
.Map(name => ExtractorOptions.ShouldExtract(name, versionSetNamesOption))
|
||||
.IfNone(true));
|
||||
builder.Services.TryAddSingleton(GetPutApiModels);
|
||||
}
|
||||
|
||||
private async ValueTask ValidateExtractedInformationFiles(IDictionary<ApiName, ApiDto> expectedResources, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
private static PutApiModels GetPutApiModels(IServiceProvider provider)
|
||||
{
|
||||
var fileResources = await getFileResources(serviceDirectory, Prelude.None, cancellationToken);
|
||||
var getServiceUri = provider.GetRequiredService<GetManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
var expected = expectedResources.MapValue(NormalizeDto);
|
||||
var actual = fileResources.MapValue(NormalizeDto);
|
||||
|
||||
actual.Should().BeEquivalentTo(expected);
|
||||
}
|
||||
private static string NormalizeDto(ApiDto dto) =>
|
||||
new
|
||||
return async (models, serviceName, cancellationToken) =>
|
||||
{
|
||||
DisplayName = dto.Properties.DisplayName ?? string.Empty,
|
||||
Path = dto.Properties.Path ?? string.Empty,
|
||||
RevisionDescription = dto.Properties.ApiRevisionDescription ?? string.Empty,
|
||||
Revision = dto.Properties.ApiRevision ?? string.Empty,
|
||||
ServiceUrl = Uri.TryCreate(dto.Properties.ServiceUrl, UriKind.Absolute, out var uri)
|
||||
? uri.RemovePath().ToString()
|
||||
: string.Empty
|
||||
}.ToString()!;
|
||||
using var _ = activitySource.StartActivity(nameof(PutApiModels));
|
||||
|
||||
private async ValueTask ValidateExtractedSpecificationFiles(IDictionary<ApiName, ApiDto> expectedResources, Option<ApiSpecification> defaultApiSpecification, ManagementServiceName serviceName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var expected = await expectedResources.ToAsyncEnumerable()
|
||||
.Choose(async kvp =>
|
||||
{
|
||||
var name = kvp.Key;
|
||||
return from specification in await GetExpectedApiSpecification(name, kvp.Value, defaultApiSpecification, serviceName, cancellationToken)
|
||||
// Skip XML specification files. Sometimes they get extracted, other times they fail.
|
||||
where specification is not (ApiSpecification.Wsdl or ApiSpecification.Wadl)
|
||||
select (name, specification);
|
||||
})
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
logger.LogInformation("Putting API models in {ServiceName}...", serviceName);
|
||||
|
||||
var actual = await ApiModule.ListSpecificationFiles(serviceDirectory, cancellationToken)
|
||||
.Select(file => (file.Parent.Name, file.Specification))
|
||||
// Skip XML specification files. Sometimes they get extracted, other times they fail.
|
||||
.Where(file => file.Specification is not (ApiSpecification.Wsdl or ApiSpecification.Wadl))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
await models.IterParallel(async model =>
|
||||
{
|
||||
async ValueTask putRevision(ApiRevision revision) => await put(model.Name, model.Type, model.Path, model.Version, revision, serviceName, cancellationToken);
|
||||
|
||||
actual.Should().BeEquivalentTo(expected);
|
||||
}
|
||||
// Put first revision to make sure it's the current revision.
|
||||
await model.Revisions.HeadOrNone().IterTask(putRevision);
|
||||
|
||||
private async ValueTask<Option<ApiSpecification>> GetExpectedApiSpecification(ApiName name, ApiDto dto, Option<ApiSpecification> defaultApiSpecification, ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
{
|
||||
switch (dto.Properties.ApiType ?? dto.Properties.Type)
|
||||
// Put other revisions
|
||||
await model.Revisions.Skip(1).IterParallel(putRevision, cancellationToken);
|
||||
}, cancellationToken);
|
||||
};
|
||||
|
||||
async ValueTask put(ApiName name, ApiType type, string path, Option<ApiVersion> version, ApiRevision revision, ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
{
|
||||
case "graphql":
|
||||
var specificationContents = await tryGetApimGraphQlSchema(name, serviceName, cancellationToken);
|
||||
return specificationContents.Map(contents => new ApiSpecification.GraphQl() as ApiSpecification);
|
||||
case "soap":
|
||||
return new ApiSpecification.Wsdl();
|
||||
case "websocket":
|
||||
return Option<ApiSpecification>.None;
|
||||
default:
|
||||
#pragma warning disable CA1849 // Call async methods when in an async method
|
||||
return defaultApiSpecification.IfNone(() => new ApiSpecification.OpenApi
|
||||
var rootName = ApiName.GetRootName(name);
|
||||
var dto = getDto(rootName, type, path, version, revision);
|
||||
var revisionedName = ApiName.GetRevisionedName(rootName, revision.Number);
|
||||
|
||||
var serviceUri = getServiceUri(serviceName);
|
||||
var uri = ApiUri.From(revisionedName, serviceUri);
|
||||
await uri.PutDto(dto, pipeline, cancellationToken);
|
||||
|
||||
if (type is ApiType.GraphQl)
|
||||
{
|
||||
await revision.Specification.IterTask(async specification => await uri.PutGraphQlSchema(BinaryData.FromString(specification), pipeline, cancellationToken));
|
||||
}
|
||||
|
||||
await ApiPolicyModule.Put(revision.Policies, revisionedName, serviceUri, pipeline, cancellationToken);
|
||||
await ApiTagModule.Put(revision.Tags, revisionedName, serviceUri, pipeline, cancellationToken);
|
||||
}
|
||||
|
||||
static ApiDto getDto(ApiName name, ApiType type, string path, Option<ApiVersion> version, ApiRevision revision) =>
|
||||
new ApiDto()
|
||||
{
|
||||
Properties = new ApiDto.ApiCreateOrUpdateProperties
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
});
|
||||
#pragma warning restore CA1849 // Call async methods when in an async method
|
||||
// APIM sets the description to null when it imports for SOAP APIs.
|
||||
DisplayName = name.ToString(),
|
||||
Path = path,
|
||||
ApiType = type switch
|
||||
{
|
||||
ApiType.Http => null,
|
||||
ApiType.Soap => "soap",
|
||||
ApiType.GraphQl => null,
|
||||
ApiType.WebSocket => null,
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
Type = type switch
|
||||
{
|
||||
ApiType.Http => "http",
|
||||
ApiType.Soap => "soap",
|
||||
ApiType.GraphQl => "graphql",
|
||||
ApiType.WebSocket => "websocket",
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
Protocols = type switch
|
||||
{
|
||||
ApiType.Http => ["http", "https"],
|
||||
ApiType.Soap => ["http", "https"],
|
||||
ApiType.GraphQl => ["http", "https"],
|
||||
ApiType.WebSocket => ["ws", "wss"],
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
ServiceUrl = revision.ServiceUri.ValueUnsafe()?.ToString(),
|
||||
ApiRevisionDescription = revision.Description.ValueUnsafe(),
|
||||
ApiRevision = $"{revision.Number.ToInt()}",
|
||||
ApiVersion = version.Map(version => version.Version).ValueUnsafe(),
|
||||
ApiVersionSetId = version.Map(version => $"/apiVersionSets/{version.VersionSetName}").ValueUnsafe()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureValidateExtractedApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureGetApimApis(builder);
|
||||
ConfigureTryGetApimGraphQlSchema(builder);
|
||||
ConfigureGetFileApis(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetValidateExtractedApis);
|
||||
}
|
||||
|
||||
private static ValidateExtractedApis GetValidateExtractedApis(IServiceProvider provider)
|
||||
{
|
||||
var getApimResources = provider.GetRequiredService<GetApimApis>();
|
||||
var tryGetApimGraphQlSchema = provider.GetRequiredService<TryGetApimGraphQlSchema>();
|
||||
var getFileResources = provider.GetRequiredService<GetFileApis>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (apiNamesOption, defaultApiSpecification, versionSetNamesOption, serviceName, serviceDirectory, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ValidateExtractedApis));
|
||||
|
||||
logger.LogInformation("Validating extracted APIs in {ServiceName}...", serviceName);
|
||||
|
||||
var expected = await getExpectedResources(apiNamesOption, versionSetNamesOption, serviceName, cancellationToken);
|
||||
|
||||
await validateExtractedInformationFiles(expected, serviceDirectory, cancellationToken);
|
||||
await validateExtractedSpecificationFiles(expected, defaultApiSpecification, serviceName, serviceDirectory, cancellationToken);
|
||||
};
|
||||
|
||||
async ValueTask<FrozenDictionary<ApiName, ApiDto>> getExpectedResources(Option<FrozenSet<ApiName>> apiNamesOption, Option<FrozenSet<VersionSetName>> versionSetNamesOption, ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
{
|
||||
var apimResources = await getApimResources(serviceName, cancellationToken);
|
||||
|
||||
return apimResources.WhereKey(name => ExtractorOptions.ShouldExtract(name, apiNamesOption))
|
||||
.WhereValue(dto => common.ApiModule.TryGetVersionSetName(dto)
|
||||
.Map(name => ExtractorOptions.ShouldExtract(name, versionSetNamesOption))
|
||||
.IfNone(true))
|
||||
.ToFrozenDictionary();
|
||||
}
|
||||
|
||||
async ValueTask validateExtractedInformationFiles(IDictionary<ApiName, ApiDto> expectedResources, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var fileResources = await getFileResources(serviceDirectory, Prelude.None, cancellationToken);
|
||||
|
||||
var expected = expectedResources.MapValue(normalizeDto)
|
||||
.ToFrozenDictionary();
|
||||
|
||||
var actual = fileResources.MapValue(normalizeDto)
|
||||
.ToFrozenDictionary();
|
||||
|
||||
actual.Should().BeEquivalentTo(expected);
|
||||
}
|
||||
|
||||
static string normalizeDto(ApiDto dto) =>
|
||||
new
|
||||
{
|
||||
DisplayName = dto.Properties.DisplayName ?? string.Empty,
|
||||
Path = dto.Properties.Path ?? string.Empty,
|
||||
RevisionDescription = dto.Properties.ApiRevisionDescription ?? string.Empty,
|
||||
Revision = dto.Properties.ApiRevision ?? string.Empty,
|
||||
ServiceUrl = Uri.TryCreate(dto.Properties.ServiceUrl, UriKind.Absolute, out var uri)
|
||||
? uri.RemovePath().ToString()
|
||||
: string.Empty
|
||||
}.ToString()!;
|
||||
|
||||
async ValueTask validateExtractedSpecificationFiles(IDictionary<ApiName, ApiDto> expectedResources, Option<ApiSpecification> defaultApiSpecification, ManagementServiceName serviceName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var expected = await expectedResources.ToAsyncEnumerable()
|
||||
.Choose(async kvp =>
|
||||
{
|
||||
var name = kvp.Key;
|
||||
return from specification in await getExpectedApiSpecification(name, kvp.Value, defaultApiSpecification, serviceName, cancellationToken)
|
||||
// Skip XML specification files. Sometimes they get extracted, other times they fail.
|
||||
where specification is not (ApiSpecification.Wsdl or ApiSpecification.Wadl)
|
||||
select (name, specification);
|
||||
})
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
|
||||
var actual = await common.ApiModule.ListSpecificationFiles(serviceDirectory)
|
||||
.Select(file => (file.Parent.Name, file.Specification))
|
||||
// Skip XML specification files. Sometimes they get extracted, other times they fail.
|
||||
.Where(file => file.Specification is not (ApiSpecification.Wsdl or ApiSpecification.Wadl))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
|
||||
actual.Should().BeEquivalentTo(expected);
|
||||
}
|
||||
|
||||
async ValueTask<Option<ApiSpecification>> getExpectedApiSpecification(ApiName name, ApiDto dto, Option<ApiSpecification> defaultApiSpecification, ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
{
|
||||
switch (dto.Properties.ApiType ?? dto.Properties.Type)
|
||||
{
|
||||
case "graphql":
|
||||
var specificationContents = await tryGetApimGraphQlSchema(name, serviceName, cancellationToken);
|
||||
return specificationContents.Map(contents => new ApiSpecification.GraphQl() as ApiSpecification);
|
||||
case "soap":
|
||||
return new ApiSpecification.Wsdl();
|
||||
case "websocket":
|
||||
return Option<ApiSpecification>.None;
|
||||
default:
|
||||
return defaultApiSpecification.IfNone(() => new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Yaml(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class GetApimApisHandler(ILogger<GetApimApis> logger, GetManagementServiceUri getServiceUri, HttpPipeline pipeline, ActivitySource activitySource)
|
||||
{
|
||||
public async ValueTask<FrozenDictionary<ApiName, ApiDto>> Handle(ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
public static void ConfigureGetApimApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(GetApimApis));
|
||||
ManagementServiceModule.ConfigureGetManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
logger.LogInformation("Getting APIs from {ServiceName}...", serviceName);
|
||||
|
||||
var serviceUri = getServiceUri(serviceName);
|
||||
var uri = ApisUri.From(serviceUri);
|
||||
|
||||
return await uri.List(pipeline, cancellationToken)
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class TryGetApimGraphQlSchemaHandler(ILogger<TryGetApimGraphQlSchema> logger, GetManagementServiceUri getServiceUri, HttpPipeline pipeline, ActivitySource activitySource)
|
||||
{
|
||||
public async ValueTask<Option<BinaryData>> Handle(ApiName name, ManagementServiceName serviceName, CancellationToken cancellationToken)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(TryGetApimGraphQlSchema));
|
||||
|
||||
logger.LogInformation("Getting GraphQL schema for {ApiName} from {ServiceName}...", name, serviceName);
|
||||
|
||||
var serviceUri = getServiceUri(serviceName);
|
||||
var uri = ApiUri.From(name, serviceUri);
|
||||
|
||||
return await uri.TryGetGraphQlSchema(pipeline, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class GetFileApisHandler(ILogger<GetFileApis> logger, ActivitySource activitySource)
|
||||
{
|
||||
public async ValueTask<FrozenDictionary<ApiName, ApiDto>> Handle(ManagementServiceDirectory serviceDirectory, Option<CommitId> commitIdOption, CancellationToken cancellationToken) =>
|
||||
await commitIdOption.Map(commitId => GetWithCommit(serviceDirectory, commitId, cancellationToken))
|
||||
.IfNone(() => GetWithoutCommit(serviceDirectory, cancellationToken));
|
||||
|
||||
private async ValueTask<FrozenDictionary<ApiName, ApiDto>> GetWithCommit(ManagementServiceDirectory serviceDirectory, CommitId commitId, CancellationToken cancellationToken)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(GetFileApis));
|
||||
|
||||
logger.LogInformation("Getting apis from {ServiceDirectory} as of commit {CommitId}...", serviceDirectory, commitId);
|
||||
|
||||
return await Git.GetExistingFilesInCommit(serviceDirectory.ToDirectoryInfo(), commitId)
|
||||
.ToAsyncEnumerable()
|
||||
.Choose(file => ApiInformationFile.TryParse(file, serviceDirectory))
|
||||
.Choose(async file => await TryGetCommitResource(commitId, serviceDirectory, file, cancellationToken))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
builder.Services.TryAddSingleton(GetGetApimApis);
|
||||
}
|
||||
|
||||
private static async ValueTask<Option<(ApiName name, ApiDto dto)>> TryGetCommitResource(CommitId commitId, ManagementServiceDirectory serviceDirectory, ApiInformationFile file, CancellationToken cancellationToken)
|
||||
private static GetApimApis GetGetApimApis(IServiceProvider provider)
|
||||
{
|
||||
var name = file.Parent.Name;
|
||||
var contentsOption = Git.TryGetFileContentsInCommit(serviceDirectory.ToDirectoryInfo(), file.ToFileInfo(), commitId);
|
||||
var getServiceUri = provider.GetRequiredService<GetManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return await contentsOption.MapTask(async contents =>
|
||||
return async (serviceName, cancellationToken) =>
|
||||
{
|
||||
using (contents)
|
||||
using var _ = activitySource.StartActivity(nameof(GetApimApis));
|
||||
|
||||
logger.LogInformation("Getting APIs from {ServiceName}...", serviceName);
|
||||
|
||||
var serviceUri = getServiceUri(serviceName);
|
||||
|
||||
return await ApisUri.From(serviceUri)
|
||||
.List(pipeline, cancellationToken)
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureTryGetApimGraphQlSchema(IHostApplicationBuilder builder)
|
||||
{
|
||||
ManagementServiceModule.ConfigureGetManagementServiceUri(builder);
|
||||
AzureModule.ConfigureHttpPipeline(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetTryGetApimGraphQlSchema);
|
||||
}
|
||||
|
||||
private static TryGetApimGraphQlSchema GetTryGetApimGraphQlSchema(IServiceProvider provider)
|
||||
{
|
||||
var getServiceUri = provider.GetRequiredService<GetManagementServiceUri>();
|
||||
var pipeline = provider.GetRequiredService<HttpPipeline>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (name, serviceName, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(TryGetApimGraphQlSchema));
|
||||
|
||||
logger.LogInformation("Getting GraphQL schema for {ApiName} from {ServiceName}...", name, serviceName);
|
||||
|
||||
var serviceUri = getServiceUri(serviceName);
|
||||
|
||||
return await ApiUri.From(name, serviceUri)
|
||||
.TryGetGraphQlSchema(pipeline, cancellationToken);
|
||||
};
|
||||
}
|
||||
|
||||
public static void ConfigureGetFileApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetGetFileApis);
|
||||
}
|
||||
|
||||
private static GetFileApis GetGetFileApis(IServiceProvider provider)
|
||||
{
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (serviceDirectory, commitIdOption, cancellationToken) =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(GetFileApis));
|
||||
|
||||
return await commitIdOption.Map(commitId => getWithCommit(serviceDirectory, commitId, cancellationToken))
|
||||
.IfNone(() => getWithoutCommit(serviceDirectory, cancellationToken));
|
||||
};
|
||||
|
||||
async ValueTask<FrozenDictionary<ApiName, ApiDto>> getWithCommit(ManagementServiceDirectory serviceDirectory, CommitId commitId, CancellationToken cancellationToken)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(GetFileApis));
|
||||
|
||||
logger.LogInformation("Getting apis from {ServiceDirectory} as of commit {CommitId}...", serviceDirectory, commitId);
|
||||
|
||||
return await Git.GetExistingFilesInCommit(serviceDirectory.ToDirectoryInfo(), commitId)
|
||||
.ToAsyncEnumerable()
|
||||
.Choose(file => ApiInformationFile.TryParse(file, serviceDirectory))
|
||||
.Choose(async file => await tryGetCommitResource(commitId, serviceDirectory, file, cancellationToken))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
}
|
||||
|
||||
static async ValueTask<Option<(ApiName name, ApiDto dto)>> tryGetCommitResource(CommitId commitId, ManagementServiceDirectory serviceDirectory, ApiInformationFile file, CancellationToken cancellationToken)
|
||||
{
|
||||
var name = file.Parent.Name;
|
||||
var contentsOption = Git.TryGetFileContentsInCommit(serviceDirectory.ToDirectoryInfo(), file.ToFileInfo(), commitId);
|
||||
|
||||
return await contentsOption.MapTask(async contents =>
|
||||
{
|
||||
var data = await BinaryData.FromStreamAsync(contents, cancellationToken);
|
||||
var dto = data.ToObjectFromJson<ApiDto>();
|
||||
return (name, dto);
|
||||
}
|
||||
});
|
||||
}
|
||||
using (contents)
|
||||
{
|
||||
var data = await BinaryData.FromStreamAsync(contents, cancellationToken);
|
||||
var dto = data.ToObjectFromJson<ApiDto>();
|
||||
return (name, dto);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async ValueTask<FrozenDictionary<ApiName, ApiDto>> GetWithoutCommit(ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(GetFileApis));
|
||||
|
||||
logger.LogInformation("Getting apis from {ServiceDirectory}...", serviceDirectory);
|
||||
|
||||
return await ApiModule.ListInformationFiles(serviceDirectory)
|
||||
.ToAsyncEnumerable()
|
||||
.SelectAwait(async file => (file.Parent.Name,
|
||||
await file.ReadDto(cancellationToken)))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
file sealed class WriteApiModelsHandler(ILogger<WriteApiModels> logger, ActivitySource activitySource)
|
||||
{
|
||||
public async ValueTask Handle(IEnumerable<ApiModel> models, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(WriteApiModels));
|
||||
|
||||
logger.LogInformation("Writing api models to {ServiceDirectory}...", serviceDirectory);
|
||||
await models.IterParallel(async model =>
|
||||
async ValueTask<FrozenDictionary<ApiName, ApiDto>> getWithoutCommit(ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
await WriteRevisionArtifacts(model, serviceDirectory, cancellationToken);
|
||||
}, cancellationToken);
|
||||
logger.LogInformation("Getting APIs from {ServiceDirectory}...", serviceDirectory);
|
||||
|
||||
return await common.ApiModule.ListInformationFiles(serviceDirectory)
|
||||
.ToAsyncEnumerable()
|
||||
.SelectAwait(async file => (file.Parent.Name,
|
||||
await file.ReadDto(cancellationToken)))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public static async ValueTask WriteArtifacts(IEnumerable<ApiModel> models, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await models.IterParallel(async model =>
|
||||
public static void ConfigureWriteApiModels(IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.TryAddSingleton(GetWriteApiModels);
|
||||
}
|
||||
|
||||
private static WriteApiModels GetWriteApiModels(IServiceProvider provider)
|
||||
{
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (models, serviceDirectory, cancellationToken) =>
|
||||
{
|
||||
await WriteRevisionArtifacts(model, serviceDirectory, cancellationToken);
|
||||
}, cancellationToken);
|
||||
using var _ = activitySource.StartActivity(nameof(WriteApiModels));
|
||||
|
||||
public static async ValueTask WriteRevisionArtifacts(ApiModel model, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await model.Revisions
|
||||
.Select((revision, index) => (revision, index))
|
||||
.IterParallel(async x =>
|
||||
{
|
||||
var (name, type, path, version, (revision, index)) = (model.Name, model.Type, model.Path, model.Version, x);
|
||||
logger.LogInformation("Writing api models to {ServiceDirectory}...", serviceDirectory);
|
||||
|
||||
await WriteInformationFile(name, type, path, version, revision, index, serviceDirectory, cancellationToken);
|
||||
await WriteSpecificationFile(name, type, revision, index, serviceDirectory, cancellationToken);
|
||||
}, cancellationToken);
|
||||
await models.IterParallel(async model =>
|
||||
{
|
||||
await writeRevisionArtifacts(model, serviceDirectory, cancellationToken);
|
||||
}, cancellationToken);
|
||||
};
|
||||
|
||||
private static async ValueTask WriteInformationFile(ApiName name, ApiType type, string path, Option<ApiVersion> version, ApiRevision revision, int index, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var apiName = GetApiName(name, revision, index);
|
||||
var informationFile = ApiInformationFile.From(apiName, serviceDirectory);
|
||||
var rootApiName = ApiName.GetRootName(name);
|
||||
var dto = GetDto(rootApiName, type, path, version, revision);
|
||||
static async ValueTask writeRevisionArtifacts(ApiModel model, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await model.Revisions
|
||||
.Select((revision, index) => (revision, index))
|
||||
.IterParallel(async x =>
|
||||
{
|
||||
var (name, type, path, version, (revision, index)) = (model.Name, model.Type, model.Path, model.Version, x);
|
||||
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
}
|
||||
await writeInformationFile(name, type, path, version, revision, index, serviceDirectory, cancellationToken);
|
||||
await writeSpecificationFile(name, type, revision, index, serviceDirectory, cancellationToken);
|
||||
}, cancellationToken);
|
||||
|
||||
private static ApiName GetApiName(ApiName name, ApiRevision revision, int index)
|
||||
{
|
||||
var rootApiName = ApiName.GetRootName(name);
|
||||
static async ValueTask writeInformationFile(ApiName name, ApiType type, string path, Option<ApiVersion> version, ApiRevision revision, int index, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var apiName = getApiName(name, revision, index);
|
||||
var informationFile = ApiInformationFile.From(apiName, serviceDirectory);
|
||||
var rootApiName = ApiName.GetRootName(name);
|
||||
var dto = getDto(rootApiName, type, path, version, revision);
|
||||
|
||||
return index == 0 ? rootApiName : ApiName.GetRevisionedName(rootApiName, revision.Number);
|
||||
}
|
||||
await informationFile.WriteDto(dto, cancellationToken);
|
||||
}
|
||||
|
||||
private static async ValueTask WriteSpecificationFile(ApiName name, ApiType type, ApiRevision revision, int index, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var specificationOption = from contents in revision.Specification
|
||||
from specification in type switch
|
||||
{
|
||||
ApiType.Http => Option<ApiSpecification>.Some(new ApiSpecification.OpenApi
|
||||
static ApiName getApiName(ApiName name, ApiRevision revision, int index)
|
||||
{
|
||||
var rootApiName = ApiName.GetRootName(name);
|
||||
|
||||
return index == 0 ? rootApiName : ApiName.GetRevisionedName(rootApiName, revision.Number);
|
||||
}
|
||||
|
||||
static async ValueTask writeSpecificationFile(ApiName name, ApiType type, ApiRevision revision, int index, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
var specificationOption = from contents in revision.Specification
|
||||
from specification in type switch
|
||||
{
|
||||
Format = new OpenApiFormat.Json(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
}),
|
||||
ApiType.GraphQl => new ApiSpecification.GraphQl(),
|
||||
ApiType.Soap => new ApiSpecification.Wsdl(),
|
||||
_ => Option<ApiSpecification>.None
|
||||
}
|
||||
select (specification, contents);
|
||||
ApiType.Http => Option<ApiSpecification>.Some(new ApiSpecification.OpenApi
|
||||
{
|
||||
Format = new OpenApiFormat.Json(),
|
||||
Version = new OpenApiVersion.V3()
|
||||
}),
|
||||
ApiType.GraphQl => new ApiSpecification.GraphQl(),
|
||||
ApiType.Soap => new ApiSpecification.Wsdl(),
|
||||
_ => Option<ApiSpecification>.None
|
||||
}
|
||||
select (specification, contents);
|
||||
|
||||
await specificationOption.IterTask(async x =>
|
||||
{
|
||||
var (specification, contents) = x;
|
||||
var apiName = GetApiName(name, revision, index);
|
||||
var specificationFile = ApiSpecificationFile.From(specification, apiName, serviceDirectory);
|
||||
await specificationFile.WriteSpecification(BinaryData.FromString(contents), cancellationToken);
|
||||
});
|
||||
}
|
||||
|
||||
private static ApiDto GetDto(ApiName name, ApiType type, string path, Option<ApiVersion> version, ApiRevision revision) =>
|
||||
new ApiDto()
|
||||
{
|
||||
Properties = new ApiDto.ApiCreateOrUpdateProperties
|
||||
await specificationOption.IterTask(async x =>
|
||||
{
|
||||
// APIM sets the description to null when it imports for SOAP APIs.
|
||||
DisplayName = name.ToString(),
|
||||
Path = path,
|
||||
ApiType = type switch
|
||||
var (specification, contents) = x;
|
||||
var apiName = getApiName(name, revision, index);
|
||||
var specificationFile = ApiSpecificationFile.From(specification, apiName, serviceDirectory);
|
||||
await specificationFile.WriteSpecification(BinaryData.FromString(contents), cancellationToken);
|
||||
});
|
||||
}
|
||||
|
||||
static ApiDto getDto(ApiName name, ApiType type, string path, Option<ApiVersion> version, ApiRevision revision) =>
|
||||
new ApiDto()
|
||||
{
|
||||
Properties = new ApiDto.ApiCreateOrUpdateProperties
|
||||
{
|
||||
ApiType.Http => null,
|
||||
ApiType.Soap => "soap",
|
||||
ApiType.GraphQl => null,
|
||||
ApiType.WebSocket => null,
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
Type = type switch
|
||||
{
|
||||
ApiType.Http => "http",
|
||||
ApiType.Soap => "soap",
|
||||
ApiType.GraphQl => "graphql",
|
||||
ApiType.WebSocket => "websocket",
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
Protocols = type switch
|
||||
{
|
||||
ApiType.Http => ["http", "https"],
|
||||
ApiType.Soap => ["http", "https"],
|
||||
ApiType.GraphQl => ["http", "https"],
|
||||
ApiType.WebSocket => ["ws", "wss"],
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
ServiceUrl = revision.ServiceUri.ValueUnsafe()?.ToString(),
|
||||
ApiRevisionDescription = revision.Description.ValueUnsafe(),
|
||||
ApiRevision = $"{revision.Number.ToInt()}",
|
||||
ApiVersion = version.Map(version => version.Version).ValueUnsafe(),
|
||||
ApiVersionSetId = version.Map(version => $"/apiVersionSets/{version.VersionSetName}").ValueUnsafe()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
file sealed class ValidatePublishedApisHandler(ILogger<ValidatePublishedApis> logger, GetFileApis getFileResources, GetApimApis getApimResources, ActivitySource activitySource)
|
||||
{
|
||||
public async ValueTask Handle(IDictionary<ApiName, ApiDto> overrides, Option<CommitId> commitIdOption, ManagementServiceName serviceName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(ValidatePublishedApis));
|
||||
|
||||
logger.LogInformation("Validating published apis in {ServiceDirectory}...", serviceDirectory);
|
||||
|
||||
var apimResources = await getApimResources(serviceName, cancellationToken);
|
||||
var fileResources = await getFileResources(serviceDirectory, commitIdOption, cancellationToken);
|
||||
|
||||
var expected = PublisherOptions.Override(fileResources, overrides)
|
||||
.MapValue(NormalizeDto);
|
||||
var actual = apimResources.MapValue(NormalizeDto);
|
||||
|
||||
actual.Should().BeEquivalentTo(expected);
|
||||
// APIM sets the description to null when it imports for SOAP APIs.
|
||||
DisplayName = name.ToString(),
|
||||
Path = path,
|
||||
ApiType = type switch
|
||||
{
|
||||
ApiType.Http => null,
|
||||
ApiType.Soap => "soap",
|
||||
ApiType.GraphQl => null,
|
||||
ApiType.WebSocket => null,
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
Type = type switch
|
||||
{
|
||||
ApiType.Http => "http",
|
||||
ApiType.Soap => "soap",
|
||||
ApiType.GraphQl => "graphql",
|
||||
ApiType.WebSocket => "websocket",
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
Protocols = type switch
|
||||
{
|
||||
ApiType.Http => ["http", "https"],
|
||||
ApiType.Soap => ["http", "https"],
|
||||
ApiType.GraphQl => ["http", "https"],
|
||||
ApiType.WebSocket => ["ws", "wss"],
|
||||
_ => throw new NotSupportedException()
|
||||
},
|
||||
ServiceUrl = revision.ServiceUri.ValueUnsafe()?.ToString(),
|
||||
ApiRevisionDescription = revision.Description.ValueUnsafe(),
|
||||
ApiRevision = $"{revision.Number.ToInt()}",
|
||||
ApiVersion = version.Map(version => version.Version).ValueUnsafe(),
|
||||
ApiVersionSetId = version.Map(version => $"/apiVersionSets/{version.VersionSetName}").ValueUnsafe()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static string NormalizeDto(ApiDto dto) =>
|
||||
new
|
||||
public static void ConfigureValidatePublishedApis(IHostApplicationBuilder builder)
|
||||
{
|
||||
ConfigureGetFileApis(builder);
|
||||
ConfigureGetApimApis(builder);
|
||||
|
||||
builder.Services.TryAddSingleton(GetValidatePublishedApis);
|
||||
}
|
||||
|
||||
private static ValidatePublishedApis GetValidatePublishedApis(IServiceProvider provider)
|
||||
{
|
||||
var getFileResources = provider.GetRequiredService<GetFileApis>();
|
||||
var getApimResources = provider.GetRequiredService<GetApimApis>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
|
||||
return async (overrides, commitIdOption, serviceName, serviceDirectory, cancellationToken) =>
|
||||
{
|
||||
DisplayName = dto.Properties.DisplayName ?? string.Empty,
|
||||
Path = dto.Properties.Path ?? string.Empty,
|
||||
RevisionDescription = dto.Properties.ApiRevisionDescription ?? string.Empty,
|
||||
Revision = dto.Properties.ApiRevision ?? string.Empty,
|
||||
// Disabling this check because there are too many edge cases //TODO - Investigate
|
||||
//ServiceUrl = Uri.TryCreate(dto.Properties.ServiceUrl, UriKind.Absolute, out var uri)
|
||||
// ? uri.RemovePath().ToString()
|
||||
// : string.Empty
|
||||
}.ToString()!;
|
||||
}
|
||||
using var _ = activitySource.StartActivity(nameof(ValidatePublishedApis));
|
||||
|
||||
internal static class ApiServices
|
||||
{
|
||||
public static void ConfigureDeleteAllApis(IServiceCollection services)
|
||||
{
|
||||
ManagementServices.ConfigureGetManagementServiceUri(services);
|
||||
logger.LogInformation("Validating published apis in {ServiceDirectory}...", serviceDirectory);
|
||||
|
||||
services.TryAddSingleton<DeleteAllApisHandler>();
|
||||
services.TryAddSingleton<DeleteAllApis>(provider => provider.GetRequiredService<DeleteAllApisHandler>().Handle);
|
||||
var apimResources = await getApimResources(serviceName, cancellationToken);
|
||||
var fileResources = await getFileResources(serviceDirectory, commitIdOption, cancellationToken);
|
||||
|
||||
var expected = PublisherOptions.Override(fileResources, overrides)
|
||||
.MapValue(normalizeDto)
|
||||
.ToFrozenDictionary();
|
||||
|
||||
var actual = apimResources.MapValue(normalizeDto)
|
||||
.ToFrozenDictionary();
|
||||
|
||||
actual.Should().BeEquivalentTo(expected);
|
||||
};
|
||||
|
||||
static string normalizeDto(ApiDto dto) =>
|
||||
new
|
||||
{
|
||||
DisplayName = dto.Properties.DisplayName ?? string.Empty,
|
||||
Path = dto.Properties.Path ?? string.Empty,
|
||||
RevisionDescription = dto.Properties.ApiRevisionDescription ?? string.Empty,
|
||||
Revision = dto.Properties.ApiRevision ?? string.Empty,
|
||||
// Disabling this check because there are too many edge cases //TODO - Investigate
|
||||
//ServiceUrl = Uri.TryCreate(dto.Properties.ServiceUrl, UriKind.Absolute, out var uri)
|
||||
// ? uri.RemovePath().ToString()
|
||||
// : string.Empty
|
||||
}.ToString()!;
|
||||
}
|
||||
|
||||
public static void ConfigurePutApiModels(IServiceCollection services)
|
||||
{
|
||||
ManagementServices.ConfigureGetManagementServiceUri(services);
|
||||
|
||||
services.TryAddSingleton<PutApiModelsHandler>();
|
||||
services.TryAddSingleton<PutApiModels>(provider => provider.GetRequiredService<PutApiModelsHandler>().Handle);
|
||||
}
|
||||
|
||||
public static void ConfigureValidateExtractedApis(IServiceCollection services)
|
||||
{
|
||||
ConfigureGetApimApis(services);
|
||||
ConfigureTryGetApimGraphQlSchema(services);
|
||||
ConfigureGetFileApis(services);
|
||||
|
||||
services.TryAddSingleton<ValidateExtractedApisHandler>();
|
||||
services.TryAddSingleton<ValidateExtractedApis>(provider => provider.GetRequiredService<ValidateExtractedApisHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureGetApimApis(IServiceCollection services)
|
||||
{
|
||||
ManagementServices.ConfigureGetManagementServiceUri(services);
|
||||
|
||||
services.TryAddSingleton<GetApimApisHandler>();
|
||||
services.TryAddSingleton<GetApimApis>(provider => provider.GetRequiredService<GetApimApisHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureTryGetApimGraphQlSchema(IServiceCollection services)
|
||||
{
|
||||
ManagementServices.ConfigureGetManagementServiceUri(services);
|
||||
|
||||
services.TryAddSingleton<TryGetApimGraphQlSchemaHandler>();
|
||||
services.TryAddSingleton<TryGetApimGraphQlSchema>(provider => provider.GetRequiredService<TryGetApimGraphQlSchemaHandler>().Handle);
|
||||
}
|
||||
|
||||
private static void ConfigureGetFileApis(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<GetFileApisHandler>();
|
||||
services.TryAddSingleton<GetFileApis>(provider => provider.GetRequiredService<GetFileApisHandler>().Handle);
|
||||
}
|
||||
|
||||
public static void ConfigureWriteApiModels(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<WriteApiModelsHandler>();
|
||||
services.TryAddSingleton<WriteApiModels>(provider => provider.GetRequiredService<WriteApiModelsHandler>().Handle);
|
||||
}
|
||||
|
||||
public static void ConfigureValidatePublishedApis(IServiceCollection services)
|
||||
{
|
||||
ConfigureGetFileApis(services);
|
||||
ConfigureGetApimApis(services);
|
||||
|
||||
services.TryAddSingleton<ValidatePublishedApisHandler>();
|
||||
services.TryAddSingleton<ValidatePublishedApis>(provider => provider.GetRequiredService<ValidatePublishedApisHandler>().Handle);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Api
|
||||
{
|
||||
public static Gen<ApiModel> GenerateUpdate(ApiModel original) =>
|
||||
from revisions in GenerateRevisionUpdates(original.Revisions, original.Type, original.Name)
|
||||
select original with
|
||||
|
@ -523,7 +553,7 @@ internal static class Api
|
|||
var newGen = ApiRevision.GenerateSet(type, name);
|
||||
var updateGen = (ApiRevision revision) => GenerateRevisionUpdate(revision, type);
|
||||
|
||||
return Fixture.GenerateNewSet(revisions, newGen, updateGen);
|
||||
return Generator.GenerateNewSet(revisions, newGen, updateGen);
|
||||
}
|
||||
|
||||
private static Gen<ApiRevision> GenerateRevisionUpdate(ApiRevision revision, ApiType type) =>
|
||||
|
@ -609,4 +639,4 @@ internal static class Api
|
|||
ApiVersionSetId = version.Map(version => $"/apiVersionSets/{version.VersionSetName}").ValueUnsafe()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace integration.tests;
|
||||
|
||||
internal static class ApiPolicy
|
||||
internal static class ApiPolicyModule
|
||||
{
|
||||
public static Gen<ApiPolicyModel> GenerateUpdate(ApiPolicyModel original) =>
|
||||
from content in ApiPolicyModel.GenerateContent()
|
||||
|
@ -79,17 +79,17 @@ internal static class ApiPolicy
|
|||
}
|
||||
|
||||
private static async ValueTask<FrozenDictionary<ApiPolicyName, ApiPolicyDto>> GetFileResources(ApiName apiName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await ApiPolicyModule.ListPolicyFiles(apiName, serviceDirectory)
|
||||
.ToAsyncEnumerable()
|
||||
.SelectAwait(async file => (file.Name,
|
||||
new ApiPolicyDto
|
||||
{
|
||||
Properties = new ApiPolicyDto.ApiPolicyContract
|
||||
{
|
||||
Value = await file.ReadPolicy(cancellationToken)
|
||||
}
|
||||
}))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
await common.ApiPolicyModule.ListPolicyFiles(apiName, serviceDirectory)
|
||||
.ToAsyncEnumerable()
|
||||
.SelectAwait(async file => (file.Name,
|
||||
new ApiPolicyDto
|
||||
{
|
||||
Properties = new ApiPolicyDto.ApiPolicyContract
|
||||
{
|
||||
Value = await file.ReadPolicy(cancellationToken)
|
||||
}
|
||||
}))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
|
||||
private static string NormalizeDto(ApiPolicyDto dto) =>
|
||||
new
|
||||
|
|
|
@ -13,7 +13,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace integration.tests;
|
||||
|
||||
internal static class ApiTag
|
||||
internal static class ApiTagModule
|
||||
{
|
||||
public static async ValueTask Put(IEnumerable<ApiTagModel> models, ApiName apiName, ManagementServiceUri serviceUri, HttpPipeline pipeline, CancellationToken cancellationToken) =>
|
||||
await models.IterParallel(async model =>
|
||||
|
@ -60,11 +60,11 @@ internal static class ApiTag
|
|||
}
|
||||
|
||||
private static async ValueTask<FrozenDictionary<TagName, ApiTagDto>> GetFileResources(ApiName apiName, ManagementServiceDirectory serviceDirectory, CancellationToken cancellationToken) =>
|
||||
await ApiTagModule.ListInformationFiles(apiName, serviceDirectory)
|
||||
.ToAsyncEnumerable()
|
||||
.SelectAwait(async file => (file.Parent.Name,
|
||||
await file.ReadDto(cancellationToken)))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
await common.ApiTagModule.ListInformationFiles(apiName, serviceDirectory)
|
||||
.ToAsyncEnumerable()
|
||||
.SelectAwait(async file => (file.Parent.Name,
|
||||
await file.ReadDto(cancellationToken)))
|
||||
.ToFrozenDictionary(cancellationToken);
|
||||
|
||||
private static string NormalizeDto(ApiTagDto dto) =>
|
||||
nameof(ApiTagDto);
|
||||
|
|
|
@ -1,30 +1,43 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using common;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace integration.tests;
|
||||
|
||||
internal delegate ValueTask RunApplication(CancellationToken cancellationToken);
|
||||
|
||||
file sealed class RunApplicationHandler(ActivitySource activitySource, RunTests runTests)
|
||||
internal static class AppModule
|
||||
{
|
||||
public async ValueTask Handle(CancellationToken cancellationToken)
|
||||
public static void ConfigureRunApplication(IHostApplicationBuilder builder)
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(RunApplication));
|
||||
TestModule.ConfigureTestExtractor(builder);
|
||||
TestModule.ConfigureTestExtractThenPublish(builder);
|
||||
TestModule.ConfigureTestPublisher(builder);
|
||||
TestModule.ConfigureCleanUpTests(builder);
|
||||
//TestModule.ConfigureTestWorkspaces(builder);
|
||||
|
||||
await runTests(cancellationToken);
|
||||
builder.Services.TryAddSingleton(GetRunApplication);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class AppServices
|
||||
{
|
||||
public static void ConfigureRunApplication(IServiceCollection services)
|
||||
private static RunApplication GetRunApplication(IServiceProvider provider)
|
||||
{
|
||||
TestServices.ConfigureRunTests(services);
|
||||
var testExtractor = provider.GetRequiredService<TestExtractor>();
|
||||
var testExtractThenPublish = provider.GetRequiredService<TestExtractThenPublish>();
|
||||
var testPublisher = provider.GetRequiredService<TestPublisher>();
|
||||
//var testWorkspaces = provider.GetRequiredService<TestWorkspaces>();
|
||||
var cleanUpTests = provider.GetRequiredService<CleanUpTests>();
|
||||
var activitySource = provider.GetRequiredService<ActivitySource>();
|
||||
|
||||
services.TryAddSingleton<RunApplicationHandler>();
|
||||
services.TryAddSingleton<RunApplication>(provider => provider.GetRequiredService<RunApplicationHandler>().Handle);
|
||||
return async cancellationToken =>
|
||||
{
|
||||
using var _ = activitySource.StartActivity(nameof(RunApplication));
|
||||
|
||||
await testExtractor(cancellationToken);
|
||||
await testExtractThenPublish(cancellationToken);
|
||||
await testPublisher(cancellationToken);
|
||||
await cleanUpTests(cancellationToken);
|
||||
//await testWorkspaces(cancellationToken);
|
||||
};
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче