diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..d6cac58 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,64 @@ +name: build +on: + push: + branches: + - main + tags: + - '*' + pull_request: + branches: + - main + workflow_dispatch: + inputs: + forcePublish: + description: When true the Publish stage will always be run, otherwise it only runs for tagged versions. + required: false + default: false + type: boolean + forcePublicNugetDestination: + description: When true the NuGet Publish destination will always be set to nuget.org. (Normally, force publishing publishes to the private feed on GitHub.) + required: false + default: false + type: boolean + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + checks: write # enable test result annotations + contents: write # enable creating releases + issues: read + packages: write # enable publishing packages + pull-requests: write # enable test result annotations + +jobs: + build: + name: Run Build + runs-on: ubuntu-latest + outputs: + semver: ${{ steps.run_build.outputs.semver }} + major: ${{ steps.run_build.outputs.major }} + majorMinor: ${{ steps.run_build.outputs.majorMinor }} + preReleaseTag: ${{ steps.run_build.outputs.preReleaseTag }} + + steps: + - uses: endjin/Endjin.RecommendedPractices.GitHubActions/actions/prepare-env-vars-and-secrets@main + id: prepareEnvVarsAndSecrets + with: + environmentVariablesYaml: | + ZF_NUGET_PUBLISH_SOURCE: ${{ (startsWith(github.ref, 'refs/tags/') || github.event.inputs.forcePublicNugetDestination == 'true') && 'https://api.nuget.org/v3/index.json' || format('https://nuget.pkg.github.com/{0}/index.json', github.repository_owner) }} + secretsYaml: | + NUGET_API_KEY: "${{ startsWith(github.ref, 'refs/tags/') && secrets.ENDJIN_NUGET_APIKEY || secrets.ENDJIN_GITHUB_PUBLISHER_PAT }}" + secretsEncryptionKey: ${{ secrets.SHARED_WORKFLOW_KEY }} + + - uses: endjin/Endjin.RecommendedPractices.GitHubActions/actions/run-build-process@main + id: run_build + with: + netSdkVersion: '8.x' + # workflow_dispatch inputs are always strings, the type property is just for the UI + forcePublish: ${{ github.event.inputs.forcePublish == 'true' }} + buildEnv: ${{ steps.prepareEnvVarsAndSecrets.outputs.environmentVariablesYamlBase64 }} + buildSecrets: ${{ steps.prepareEnvVarsAndSecrets.outputs.secretsYamlBase64 }} + token: ${{ secrets.GITHUB_TOKEN }} + secretsEncryptionKey: ${{ secrets.SHARED_WORKFLOW_KEY}} diff --git a/.gitignore b/.gitignore index 140a41b..0b8fc53 100644 --- a/.gitignore +++ b/.gitignore @@ -346,6 +346,15 @@ healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ +# Cobertura code coverage file +coverage.cobertura.xml + # Ionide (cross platform F# VS Code tools) working folder .ionide/ /Solutions/AzAppConfigToUserSecrets.Cli/Properties/launchSettings.json + +# build outputs +_codeCoverage/ +_packages/ +.zf/extensions/ +*.sbom.* \ No newline at end of file diff --git a/.zf/config.ps1 b/.zf/config.ps1 new file mode 100644 index 0000000..c9b5418 --- /dev/null +++ b/.zf/config.ps1 @@ -0,0 +1,63 @@ +<# +This example demonstrates a software build process using the 'ZeroFailed.Build.DotNet' extension +to provide the features needed when building a .NET solutions. +#> + +$zerofailedExtensions = @( + @{ + # References the extension from its GitHub repository. If not already installed, use latest version from 'main' will be downloaded. + Name = "ZeroFailed.Build.DotNet" + GitRepository = "https://github.com/zerofailed/ZeroFailed.Build.DotNet" + GitRef = "main" + } +) + +# Load the tasks and process +. ZeroFailed.tasks -ZfPath $here/.zf + +# +# Build process configuration +# +# +# Build process control options +# +$SkipInit = $false +$SkipVersion = $false +$SkipBuild = $false +$CleanBuild = $Clean +$SkipTest = $false +$SkipTestReport = $false +$SkipAnalysis = $false +$SkipPackage = $false + +$SolutionToBuild = (Resolve-Path (Join-Path $here ".\Solutions\AzAppConfigToUserSecrets.sln")).Path +$IncludeAssembliesInCodeCoverage = "AzAppConfigToUserSecrets*" +$NugetPublishSource = property ZF_NUGET_PUBLISH_SOURCE "$here/_local-nuget-feed" +$ProjectsToPublish = @() + + +# Customise the build process +task . FullBuild + +# +# Build Process Extensibility Points - uncomment and implement as required +# + +# task RunFirst {} +# task PreInit {} +# task PostInit {} +# task PreVersion {} +# task PostVersion {} +# task PreBuild {} +# task PostBuild {} +# task PreTest {} +# task PostTest {} +# task PreTestReport {} +# task PostTestReport {} +# task PreAnalysis {} +# task PostAnalysis {} +# task PrePackage {} +# task PostPackage {} +# task PrePublish {} +# task PostPublish {} +# task RunLast {} diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/AzAppConfigToUserSecrets.Cli.csproj b/Solutions/AzAppConfigToUserSecrets.Cli/AzAppConfigToUserSecrets.Cli.csproj index 1730bdc..f1d9964 100644 --- a/Solutions/AzAppConfigToUserSecrets.Cli/AzAppConfigToUserSecrets.Cli.csproj +++ b/Solutions/AzAppConfigToUserSecrets.Cli/AzAppConfigToUserSecrets.Cli.csproj @@ -4,7 +4,7 @@ Exe - net6.0 + net8.0 enable enable @@ -26,24 +26,16 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - + + + - diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/CommandLineParser.cs b/Solutions/AzAppConfigToUserSecrets.Cli/CommandLineParser.cs deleted file mode 100644 index dfb3ad5..0000000 --- a/Solutions/AzAppConfigToUserSecrets.Cli/CommandLineParser.cs +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -using System.CommandLine; -using System.CommandLine.Builder; -using System.CommandLine.Invocation; -using System.CommandLine.Parsing; -using AzAppConfigToUserSecrets.Cli; -using AzAppConfigToUserSecrets.Cli.Infrastructure; - -/// -/// Parses the Command Line Args. -/// -internal class CommandLineParser -{ - private readonly ICompositeConsole console; - - /// - /// Create a new instance of . - /// - /// CompositeConsole to write output to. - public CommandLineParser(ICompositeConsole console) - { - this.console = console; - } - - /// - /// Represents the method to invoke when the export command is requested. - /// - /// Azure AD Tenant Id. - /// User Secret Id to write settings to. - /// Azure App Configuration Service URL endpoint. - /// Console to write output to. - /// System.CommandLine InvocationContext for Command Line Args. - /// Whether the command executed correctly. - public delegate Task Export(string tenantId, string userSecretsId, string endpoint, ICompositeConsole console, InvocationContext? invocationContext = null); - - /// - /// Creates configured Command Line Parser. - /// - /// Method to invoke when the export command is requested. - /// New Command Line Parser. - public Parser Create(Export? export = null) - { - // if environmentInit hasn't been provided (for testing) then assign the Command Handler - export ??= ExportHandler.ExecuteAsync; - - RootCommand rootCommand = Root(); - rootCommand.AddCommand(Export()); - - var commandBuilder = new CommandLineBuilder(rootCommand); - - return commandBuilder.UseDefaults().Build(); - - static RootCommand Root() - { - return new RootCommand - { - Name = "actus", - Description = "Export Azure App Configuration to .NET User Secrets", - }; - } - - Command Export() - { - var cmd = new Command("export", "Exports settings from Azure App Configuration to .NET User Secrets."); - - var tenantIdArg = new Option("--tenant-id") - { - Description = "Id of AAD Tenant that contains your App Configuration Service", - Arity = ArgumentArity.ExactlyOne, - IsRequired = true, - }; - - var userSecretsIdArg = new Option("--user-secrets-id") - { - Description = "User Secrets Id for your application", - Arity = ArgumentArity.ExactlyOne, - IsRequired = true, - }; - - var endpointArg = new Option("--endpoint") - { - Description = "Azure Application Configuration Service endpoint (URI)", - Arity = ArgumentArity.ExactlyOne, - IsRequired = true, - }; - - cmd.AddOption(tenantIdArg); - cmd.AddOption(userSecretsIdArg); - cmd.AddOption(endpointArg); - - cmd.SetHandler(async (context) => - { - string? tenantId = context.ParseResult.GetValueForOption(tenantIdArg); - string? userSecretsId = context.ParseResult.GetValueForOption(userSecretsIdArg); - string? endpoint = context.ParseResult.GetValueForOption(endpointArg); - - await export(tenantId!, userSecretsId!, endpoint!, (ICompositeConsole)context.Console, context) - .ConfigureAwait(false); - }); - - return cmd; - } - } -} \ No newline at end of file diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/Commands/ExportCommand.cs b/Solutions/AzAppConfigToUserSecrets.Cli/Commands/ExportCommand.cs new file mode 100644 index 0000000..3d965ad --- /dev/null +++ b/Solutions/AzAppConfigToUserSecrets.Cli/Commands/ExportCommand.cs @@ -0,0 +1,38 @@ +// +// Copyright (c) Endjin Limited. All rights reserved. +// + +using AzAppConfigToUserSecrets.Cli.Commands.Settings; +using AzAppConfigToUserSecrets.Cli.Handlers; +using Spectre.Console; +using Spectre.Console.Cli; + +namespace AzAppConfigToUserSecrets.Cli.Commands; + +/// +/// Command to export settings from Azure App Configuration to .NET User Secrets. +/// +public class ExportCommand : AsyncCommand +{ + /// + /// Executes the export command. + /// + /// The command context. + /// The command settings. + /// The exit code. + public override async Task ExecuteAsync(CommandContext context, ExportSettings settings) + { + try + { + return await ExportHandler.ExecuteAsync( + settings.TenantId, + settings.UserSecretsId, + settings.Endpoint).ConfigureAwait(false); + } + catch (Exception ex) + { + AnsiConsole.WriteException(ex); + return 1; + } + } +} \ No newline at end of file diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/Commands/Settings/ExportSettings.cs b/Solutions/AzAppConfigToUserSecrets.Cli/Commands/Settings/ExportSettings.cs new file mode 100644 index 0000000..45651a8 --- /dev/null +++ b/Solutions/AzAppConfigToUserSecrets.Cli/Commands/Settings/ExportSettings.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) Endjin Limited. All rights reserved. +// + +using System.ComponentModel; +using Spectre.Console.Cli; + +namespace AzAppConfigToUserSecrets.Cli.Commands.Settings; + +/// +/// Settings for the export command. +/// +public class ExportSettings : CommandSettings +{ + /// + /// Gets or sets the Azure AD Tenant ID. + /// + [CommandOption("--tenant-id")] + [Description("Id of AAD Tenant that contains your App Configuration Service")] + public required string TenantId { get; set; } + + /// + /// Gets or sets the User Secrets ID. + /// + [CommandOption("--user-secrets-id")] + [Description("User Secrets Id for your application")] + public required string UserSecretsId { get; set; } + + /// + /// Gets or sets the Azure App Configuration endpoint. + /// + [CommandOption("--endpoint")] + [Description("Azure Application Configuration Service endpoint (URI)")] + public required string Endpoint { get; set; } +} \ No newline at end of file diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/ExportHandler.cs b/Solutions/AzAppConfigToUserSecrets.Cli/Handlers/ExportHandler.cs similarity index 63% rename from Solutions/AzAppConfigToUserSecrets.Cli/ExportHandler.cs rename to Solutions/AzAppConfigToUserSecrets.Cli/Handlers/ExportHandler.cs index aa285ce..612e154 100644 --- a/Solutions/AzAppConfigToUserSecrets.Cli/ExportHandler.cs +++ b/Solutions/AzAppConfigToUserSecrets.Cli/Handlers/ExportHandler.cs @@ -1,16 +1,14 @@ -// +// // Copyright (c) Endjin Limited. All rights reserved. // -using System.CommandLine.Invocation; -using AzAppConfigToUserSecrets.Cli.Infrastructure; using Azure; using Azure.Data.AppConfiguration; using Azure.Identity; using Azure.Security.KeyVault.Secrets; using Spectre.Console; -namespace AzAppConfigToUserSecrets.Cli; +namespace AzAppConfigToUserSecrets.Cli.Handlers; /// /// Exports settings data from the Azure App Configuration Service to .NET User Settings. @@ -23,24 +21,20 @@ internal static class ExportHandler /// Azure AD Tenant Id. /// User Secret Id to write settings to. /// Azure App Configuration Service URL endpoint. - /// Console to write output to. - /// System.CommandLine InvocationContext for Command Line Args. /// Whether the command executed successfully. public static async Task ExecuteAsync( string tenantId, string userSecretsId, - string endpoint, - ICompositeConsole console, - InvocationContext? context = null) + string endpoint) { - await console.Status().StartAsync("Thinking...", async ctx => + await AnsiConsole.Status().StartAsync("Thinking...", async ctx => { - var credentials = new InteractiveBrowserCredential(new InteractiveBrowserCredentialOptions { TenantId = tenantId }); - var client = new ConfigurationClient(new Uri(endpoint), credentials); - var selector = new SettingSelector { Fields = SettingFields.All }; + InteractiveBrowserCredential credentials = new(new InteractiveBrowserCredentialOptions { TenantId = tenantId }); + ConfigurationClient client = new(new Uri(endpoint), credentials); + SettingSelector selector = new() { Fields = SettingFields.All }; Pageable settings = client.GetConfigurationSettings(selector); - var userSecrets = new UserSecrets(userSecretsId); + UserSecrets userSecrets = new(userSecretsId); IDictionary secrets = userSecrets.Load(); ctx.Status($"Authentication against Azure Tenant {tenantId}"); @@ -50,8 +44,8 @@ await console.Status().StartAsync("Thinking...", async ctx => if (setting is SecretReferenceConfigurationSetting secretReference) { - var identifier = new KeyVaultSecretIdentifier(secretReference.SecretId); - var secretClient = new SecretClient(identifier.VaultUri, credentials); + KeyVaultSecretIdentifier identifier = new(secretReference.SecretId); + SecretClient secretClient = new(identifier.VaultUri, credentials); Response? secret = await secretClient.GetSecretAsync(identifier.Name, identifier.Version); userSecrets.Set(setting.Key, secret.Value.Value); @@ -67,7 +61,7 @@ await console.Status().StartAsync("Thinking...", async ctx => await userSecrets.SaveAsync().ConfigureAwait(false); }).ConfigureAwait(false); - console.WriteLine("All Done!"); + AnsiConsole.WriteLine("All Done!"); return 0; } diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/AnsiConsoleStreamWriter.cs b/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/AnsiConsoleStreamWriter.cs deleted file mode 100644 index d033f85..0000000 --- a/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/AnsiConsoleStreamWriter.cs +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -using System.CommandLine.IO; -using Spectre.Console; - -namespace AzAppConfigToUserSecrets.Cli.Infrastructure; - -/// -/// Write to . -/// -internal sealed class AnsiConsoleStreamWriter : IStandardStreamWriter -{ - private readonly IAnsiConsole console; - - /// - /// Create a new AnsiConsoleStreamWriter. - /// - /// Represents a console. - public AnsiConsoleStreamWriter(IAnsiConsole console) - { - this.console = console; - } - - /// - public void Write(string? value) - { - this.console.Write(value!); - } -} \ No newline at end of file diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/CompositeConsole.cs b/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/CompositeConsole.cs deleted file mode 100644 index 506e897..0000000 --- a/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/CompositeConsole.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -using System.CommandLine.IO; -using Spectre.Console; -using Spectre.Console.Rendering; - -namespace AzAppConfigToUserSecrets.Cli.Infrastructure; - -/// -/// Provides interoperability between System.CommandLine and Spectre.Console. -/// -internal sealed class CompositeConsole : ICompositeConsole -{ - private readonly AnsiConsoleStreamWriter standardOut; - private readonly IStandardStreamWriter standardError; - - /// - /// Create a new instance of CompositeConsole. - /// - public CompositeConsole() - { - this.standardOut = new AnsiConsoleStreamWriter(AnsiConsole.Console); - this.standardError = StandardStreamWriter.Create(Console.Error); - } - - /// - bool IStandardOut.IsOutputRedirected => Console.IsOutputRedirected; - - /// - bool IStandardError.IsErrorRedirected => Console.IsErrorRedirected; - - /// - bool IStandardIn.IsInputRedirected => Console.IsInputRedirected; - - /// - IStandardStreamWriter IStandardOut.Out => this.standardOut; - - /// - IStandardStreamWriter IStandardError.Error => this.standardError; - - /// - public Profile Profile => AnsiConsole.Console.Profile; - - /// - public IAnsiConsoleCursor Cursor => AnsiConsole.Console.Cursor; - - /// - public IAnsiConsoleInput Input => AnsiConsole.Console.Input; - - /// - public IExclusivityMode ExclusivityMode => AnsiConsole.Console.ExclusivityMode; - - /// - public RenderPipeline Pipeline => AnsiConsole.Console.Pipeline; - - /// - public void Clear(bool home) - { - AnsiConsole.Console.Clear(home); - } - - /// - public void Write(IRenderable renderable) - { - AnsiConsole.Console.Write(renderable); - } -} \ No newline at end of file diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/ICompositeConsole.cs b/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/ICompositeConsole.cs deleted file mode 100644 index 05d78cc..0000000 --- a/Solutions/AzAppConfigToUserSecrets.Cli/Infrastructure/ICompositeConsole.cs +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -using System.CommandLine; -using Spectre.Console; - -namespace AzAppConfigToUserSecrets.Cli.Infrastructure; - -/// -/// Interface which enabled interop between System.CommandLine and Spectre.Console. -/// -public interface ICompositeConsole : IConsole, IAnsiConsole -{ -} \ No newline at end of file diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/Program.cs b/Solutions/AzAppConfigToUserSecrets.Cli/Program.cs index 9dbc75c..59243a6 100644 --- a/Solutions/AzAppConfigToUserSecrets.Cli/Program.cs +++ b/Solutions/AzAppConfigToUserSecrets.Cli/Program.cs @@ -2,9 +2,17 @@ // Copyright (c) Endjin Limited. All rights reserved. // -using System.CommandLine.Parsing; -using AzAppConfigToUserSecrets.Cli.Infrastructure; +using AzAppConfigToUserSecrets.Cli.Commands; +using Spectre.Console.Cli; -ICompositeConsole console = new CompositeConsole(); +CommandApp app = new(); -return await new CommandLineParser(console).Create().InvokeAsync(args, console).ConfigureAwait(false); \ No newline at end of file +app.Configure(config => +{ + config.SetApplicationName("actus"); + config.SetApplicationVersion("1.0.0"); + config.AddCommand("export") + .WithDescription("Exports settings from Azure App Configuration to .NET User Secrets."); +}); + +return await app.RunAsync(args); \ No newline at end of file diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/UserSecrets.cs b/Solutions/AzAppConfigToUserSecrets.Cli/UserSecrets.cs index 0c2118a..9b7fd62 100644 --- a/Solutions/AzAppConfigToUserSecrets.Cli/UserSecrets.cs +++ b/Solutions/AzAppConfigToUserSecrets.Cli/UserSecrets.cs @@ -37,7 +37,7 @@ public UserSecrets(string userSecretsId) /// /// Key to store the value. /// Value to store. - public void Set(string key, string value) => this.secrets[key] = value; + public void Set(string key, string? value) => this.secrets[key] = value; /// /// Save the User Secrets Store for the currently set values. @@ -45,7 +45,15 @@ public UserSecrets(string userSecretsId) /// A representing the asynchronous save operation. public async Task SaveAsync() { - string? secretsFilePath = PathHelper.GetSecretsPathFromSecretsId(this.userSecretsId); + string secretsFilePath = PathHelper.GetSecretsPathFromSecretsId(this.userSecretsId); + + // Ensure directory exists + string? directoryPath = Path.GetDirectoryName(secretsFilePath); + if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + JsonObject jsonObject = new(); foreach (KeyValuePair keyValuePair in this.secrets.AsEnumerable()) @@ -62,17 +70,24 @@ public async Task SaveAsync() /// Configuration Settings saved in the User Secrets Store. public IDictionary Load() { - string? secretsFilePath = PathHelper.GetSecretsPathFromSecretsId(this.userSecretsId); + string secretsFilePath = PathHelper.GetSecretsPathFromSecretsId(this.userSecretsId); - this.secrets = new ConfigurationBuilder() - .AddJsonFile(secretsFilePath, true) - .Build() - .AsEnumerable() - .Where(i => i.Value != null) - .ToDictionary( - i => i.Key, - i => i.Value, - StringComparer.OrdinalIgnoreCase); + if (File.Exists(secretsFilePath)) + { + this.secrets = new ConfigurationBuilder() + .AddJsonFile(secretsFilePath, true) + .Build() + .AsEnumerable() + .Where(i => i.Value != null) + .ToDictionary( + i => i.Key, + i => i.Value, + StringComparer.OrdinalIgnoreCase); + } + else + { + this.secrets = new Dictionary(); + } return this.secrets; } diff --git a/Solutions/AzAppConfigToUserSecrets.Cli/packages.lock.json b/Solutions/AzAppConfigToUserSecrets.Cli/packages.lock.json index d12abeb..21118d2 100644 --- a/Solutions/AzAppConfigToUserSecrets.Cli/packages.lock.json +++ b/Solutions/AzAppConfigToUserSecrets.Cli/packages.lock.json @@ -1,444 +1,226 @@ { "version": 1, "dependencies": { - "net6.0": { + "net8.0": { "Azure.Data.AppConfiguration": { "type": "Direct", - "requested": "[1.2.0, )", - "resolved": "1.2.0", - "contentHash": "KA1dAM9TuDsq0CRFd+3cJTYUAzA2z9N8t9/xKdDbP9URuReq/NDFcKYr7GW2W9xzVGDtCHlD5j5am/+zLLBdSg==", + "requested": "[1.6.1, )", + "resolved": "1.6.1", + "contentHash": "Vlc3hlCAsAf7BU8nH91sc6al++SmBfifF7BEol7SlRHxZKO7yC/UvduxHKytSBtdArYgsocaxUKZ8II55UfwTw==", "dependencies": { - "Azure.Core": "1.20.0", - "Microsoft.Bcl.AsyncInterfaces": "1.0.0", - "System.Text.Json": "4.6.0" + "Azure.Core": "1.46.0" } }, "Azure.Identity": { "type": "Direct", - "requested": "[1.8.0, )", - "resolved": "1.8.0", - "contentHash": "xnsY/lgAG4bO5d2akXc1hqfvknIk+u3gh5Ma33KN2uyNeU3C5AzIfrwO/N/b9D/7dk4MyXai4JGKHNgHjcoFsA==", + "requested": "[1.14.0, )", + "resolved": "1.14.0", + "contentHash": "xQ6mpNhifb8W/KG2BclhbJWAupvE3JF8lPEBF8t59Q5sc1yN0Ci+dvS0qXtc6m9auxwYpmc8rhOmK541dcGwmA==", "dependencies": { - "Azure.Core": "1.25.0", - "Microsoft.Identity.Client": "4.46.0", - "Microsoft.Identity.Client.Extensions.Msal": "2.23.0", - "System.Memory": "4.5.4", - "System.Security.Cryptography.ProtectedData": "4.7.0", - "System.Text.Json": "4.7.2", - "System.Threading.Tasks.Extensions": "4.5.4" + "Azure.Core": "1.46.1", + "Microsoft.Identity.Client": "4.71.1", + "Microsoft.Identity.Client.Extensions.Msal": "4.71.1", + "System.Memory": "4.5.5" } }, "Azure.Security.KeyVault.Secrets": { "type": "Direct", - "requested": "[4.4.0, )", - "resolved": "4.4.0", - "contentHash": "BoFpZkBU6e3kXl58xG/0FwzZ79IUcJM3tAr3m74mxL0FVG24qQeMsm8/Wis+jYtixVbk+UmsUgKN6ut0tDimnQ==", + "requested": "[4.7.0, )", + "resolved": "4.7.0", + "contentHash": "uOPCojkm41V4dKTORyGzl3/f/lriKpxSQ43fWDn4StRJBVmbF1F/DNWJhwm207kCnqgE/W9+tskJSimIKHCZkw==", "dependencies": { - "Azure.Core": "1.23.0", - "System.Memory": "4.5.4", - "System.Text.Json": "4.7.2", + "Azure.Core": "1.44.1", + "System.Memory": "4.5.5", + "System.Text.Json": "6.0.10", "System.Threading.Tasks.Extensions": "4.5.4" } }, "Endjin.RecommendedPractices.GitHub": { "type": "Direct", - "requested": "[2.1.3, )", - "resolved": "2.1.3", - "contentHash": "s9VnymeP3idpWqXaIvQGjmtRls4BXS/kcI7IskPbha+2s3oeY+xtHBNwF0NkwsdwECcCiakjkixM6w8/KcwhUw==", + "requested": "[2.1.18, )", + "resolved": "2.1.18", + "contentHash": "5zdIpj3qn+hQKvpkJO77wW74S4w8UKE0l8oDIm6jq70X7O0iNfgD+0FzEKXIYM17JtqnVSVaBd4ZyuDxHqVnLg==", "dependencies": { - "Endjin.RecommendedPractices": "2.1.3", + "Endjin.RecommendedPractices": "2.1.18", "Microsoft.SourceLink.GitHub": "1.1.1" } }, "Microsoft.Extensions.Configuration.UserSecrets": { "type": "Direct", - "requested": "[7.0.0, )", - "resolved": "7.0.0", - "contentHash": "33HPW1PmB2RS0ietBQyvOxjp4O3wlt+4tIs8KPyMn1kqp04goiZGa7+3mc69NRLv6bphkLDy0YR7Uw3aZyf8Zw==", + "requested": "[8.0.*, )", + "resolved": "8.0.1", + "contentHash": "7tYqdPPpAK+3jO9d5LTuCK2VxrEdf85Ol4trUr6ds4jclBecadWZ/RyPCbNjfbN5iGTfUnD/h65TOQuqQv2c+A==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", - "Microsoft.Extensions.Configuration.Json": "7.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", - "Microsoft.Extensions.FileProviders.Physical": "7.0.0" + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Json": "8.0.1", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0" } }, "Roslynator.Analyzers": { "type": "Direct", - "requested": "[4.1.2, )", - "resolved": "4.1.2", - "contentHash": "bNl3GRSBFjJymYnwq/IRDD9MOSZz9VKdGk9RsN0MWIXoSRnVKQv84f6s9nLE13y20lZgMZKlDqGw2uInBH4JgA==" + "requested": "[4.13.1, )", + "resolved": "4.13.1", + "contentHash": "KZpLy6ZlCebMk+d/3I5KU2R7AOb4LNJ6tPJqPtvFXmO8bEBHQvCIAvJOnY2tu4C9/aVOROTDYUFADxFqw1gh/g==" }, "Spectre.Console": { "type": "Direct", - "requested": "[0.45.0, )", - "resolved": "0.45.0", - "contentHash": "e//13o8/BCrWmwN26eJ4zCzD2iq7iUlqQd+nDI9nJUdnJ/rYAanYiNFZZ7YHwlv48IKuKtRYYP6/wPt1DG67ww==", - "dependencies": { - "System.Memory": "4.5.5" - } - }, - "StyleCop.Analyzers": { - "type": "Direct", - "requested": "[1.2.0-beta.435, )", - "resolved": "1.2.0-beta.435", - "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", - "dependencies": { - "StyleCop.Analyzers.Unstable": "1.2.0.435" - } - }, - "System.CommandLine": { - "type": "Direct", - "requested": "[2.0.0-beta4.22272.1, )", - "resolved": "2.0.0-beta4.22272.1", - "contentHash": "1uqED/q2H0kKoLJ4+hI2iPSBSEdTuhfCYADeJrAqERmiGQ2NNacYKRNEQ+gFbU4glgVyK8rxI+ZOe1onEtr/Pg==" - }, - "System.CommandLine.Experimental": { - "type": "Direct", - "requested": "[0.3.0-alpha.19577.1, )", - "resolved": "0.3.0-alpha.19577.1", - "contentHash": "d6t9G4NGBq7rB2Gvo5WjV4YuIJcplYj1fGeTef77TQJNXaExW1C4kDsyee9kHlHLejxEEtCrPvZ4pfj0IjfgHQ==", + "requested": "[0.50.0, )", + "resolved": "0.50.0", + "contentHash": "gkwYncFqMjlPF6Yz8KeVsKWpdfv15sr6uKm+vXVa/8Q4tvx52LPzMQOO5m+bXwI3AGGFeY3cok3ZJbguYizswg==", "dependencies": { - "Microsoft.CSharp": "4.4.1", - "system.memory": "4.5.3" + "System.Memory": "4.6.3" } }, - "System.CommandLine.Hosting": { + "Spectre.Console.Cli": { "type": "Direct", - "requested": "[0.4.0-alpha.22272.1, )", - "resolved": "0.4.0-alpha.22272.1", - "contentHash": "x9JhHxBLxlKyCIZADFYC8q16L9yGHdTakrLFjHabwR7Tk0761aTexiGgMTIS744HGuhc8pk9MoLUzsr/TlRfMQ==", + "requested": "[0.50.0, )", + "resolved": "0.50.0", + "contentHash": "PrctsupqHEbyoP/iRL30awUWB0Z91i21myKl70qcPwoH6marEPkPyaPgzc37xFm9QSx+/jVBQGUH7tsn0mWGNQ==", "dependencies": { - "Microsoft.Extensions.Hosting": "6.0.0", - "System.CommandLine": "2.0.0-beta4.22272.1", - "System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1" + "Spectre.Console": "0.50.0" } }, - "System.CommandLine.Rendering": { + "StyleCop.Analyzers": { "type": "Direct", - "requested": "[0.4.0-alpha.22272.1, )", - "resolved": "0.4.0-alpha.22272.1", - "contentHash": "PQd7HStYn6RYjc5zuerR41sALm3qFDutzDHISB5DYbExSgll6s8zghfyYFdLioLPWpFxVyMj3L9Ki69jqqum/g==", + "requested": "[1.2.0-beta.556, )", + "resolved": "1.2.0-beta.556", + "contentHash": "llRPgmA1fhC0I0QyFLEcjvtM2239QzKr/tcnbsjArLMJxJlu0AA5G7Fft0OI30pHF3MW63Gf4aSSsjc5m82J1Q==", "dependencies": { - "Microsoft.CSharp": "4.7.0", - "System.CommandLine": "2.0.0-beta4.22272.1" + "StyleCop.Analyzers.Unstable": "1.2.0.556" } }, "Azure.Core": { "type": "Transitive", - "resolved": "1.25.0", - "contentHash": "X8Dd4sAggS84KScWIjEbFAdt2U1KDolQopTPoHVubG2y3CM54f9l6asVrP5Uy384NWXjsspPYaJgz5xHc+KvTA==", + "resolved": "1.46.1", + "contentHash": "iE5DPOlGsN5kCkF4gN+vasN1RihO0Ypie92oQ5tohQYiokmnrrhLnee+3zcE8n7vB6ZAzhPTfUGAEXX/qHGkYA==", "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "1.1.1", - "System.Diagnostics.DiagnosticSource": "4.6.0", - "System.Memory.Data": "1.0.2", - "System.Numerics.Vectors": "4.5.0", - "System.Text.Encodings.Web": "4.7.2", - "System.Text.Json": "4.7.2", - "System.Threading.Tasks.Extensions": "4.5.4" + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.ClientModel": "1.4.1", + "System.Memory.Data": "6.0.1" } }, "Endjin.RecommendedPractices": { "type": "Transitive", - "resolved": "2.1.3", - "contentHash": "QGtkNwaXuuXw1bakDHscGReAP3c/JnzH9zTYj2YdONs1V/tD26m5GKle3nXAs9JCps3nXbUIIlYjsJsgDHNcmA==", + "resolved": "2.1.18", + "contentHash": "AAD5aVVKTdFYsMpdHft4Q4rPdLaBt/IG4K2ozmB0qkotXpIWBhNUDtguBZCkYvTt0o2UXS5fQDP3os86F03lpw==", "dependencies": { "Microsoft.Build.Tasks.Git": "1.1.1" } }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "yuvf07qFWFqtK3P/MRkEKLhn5r2UbSpVueRziSqj0yJQIKFwG1pq9mOayK3zE5qZCTs0CbrwL9M6R8VwqyGy2w==" + "resolved": "8.0.0", + "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==" }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "1.1.1", "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" - }, "Microsoft.Extensions.Configuration": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "tldQUBWt/xeH2K7/hMPPo5g8zuLc3Ro9I5d4o/XrxvxOCA2EZBtW7bCHHTc49fcBtvB8tLAb/Qsmfrq+2SJ4vA==", + "resolved": "8.0.0", + "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", - "Microsoft.Extensions.Primitives": "7.0.0" + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Configuration.Abstractions": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==", - "dependencies": { - "Microsoft.Extensions.Primitives": "7.0.0" - } - }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "b3ErKzND8LIC7o08QAVlKfaEIYEvLJbtmVbFZVBRXeu9YkKfSSzLZfR1SUfQPBIy9mKLhEtJgGYImkcMNaKE0A==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.CommandLine": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "3nL1qCkZ1Oxx14ZTzgo4MmlO7tso7F+TtMZAY2jUAtTLyAcDp+EDjk3RqafoKiNaePyPvvlleEcBxh3b2Hzl1g==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.EnvironmentVariables": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "DjYkzqvhiHCq38LW71PcIxXk6nhtV6VySP9yDcSO0goPl7YCU1VG1f2Wbgy58lkA10pWkjHCblZPUyboCB93ZA==", + "resolved": "8.0.0", + "contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Configuration.FileExtensions": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "xk2lRJ1RDuqe57BmgvRPyCt6zyePKUmvT6iuXqiHR+/OIIgWVR8Ff5k2p6DwmqY8a17hx/OnrekEhziEIeQP6Q==", + "resolved": "8.0.1", + "contentHash": "EJzSNO9oaAXnTdtdNO6npPRsIIeZCBSNmdQ091VDO7fBiOtJAAeEq6dtrVXIi3ZyjC5XRSAtVvF8SzcneRHqKQ==", "dependencies": { - "Microsoft.Extensions.Configuration": "7.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", - "Microsoft.Extensions.FileProviders.Physical": "7.0.0", - "Microsoft.Extensions.Primitives": "7.0.0" + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Configuration.Json": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "LDNYe3uw76W35Jci+be4LDf2lkQZe0A7EEYQVChFbc509CpZ4Iupod8li4PUXPBhEUOFI/rlQNf5xkzJRQGvtA==", + "resolved": "8.0.1", + "contentHash": "L89DLNuimOghjV3tLx0ArFDwVEJD6+uGB3BMCMX01kaLzXkaXHb2021xOMl2QOxUxbdePKUZsUY7n2UUkycjRg==", "dependencies": { - "Microsoft.Extensions.Configuration": "7.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "7.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", - "System.Text.Json": "7.0.0" - } - }, - "Microsoft.Extensions.DependencyInjection": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0" + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.1", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0" } }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==" + "resolved": "8.0.2", + "contentHash": "3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==" }, "Microsoft.Extensions.FileProviders.Abstractions": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==", + "resolved": "8.0.0", + "contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", "dependencies": { - "Microsoft.Extensions.Primitives": "7.0.0" + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.FileProviders.Physical": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "K8D2MTR+EtzkbZ8z80LrG7Ur64R7ZZdRLt1J5cgpc/pUWl0C6IkAUapPuK28oionHueCPELUqq0oYEvZfalNdg==", + "resolved": "8.0.0", + "contentHash": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", "dependencies": { - "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", - "Microsoft.Extensions.FileSystemGlobbing": "7.0.0", - "Microsoft.Extensions.Primitives": "7.0.0" + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.FileSystemGlobbing": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "2jONjKHiF+E92ynz2ZFcr9OvxIw+rTGMPEH+UZGeHTEComVav93jQUWGkso8yWwVBcEJGcNcZAaqY01FFJcj7w==" - }, - "Microsoft.Extensions.Hosting": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "M8VzD0ni5VarIRT8njnwK4K2WSAo0kZH4Zc3mKcSGkP4CjDZ91T9ZEFmmwhmo4z7x8AFq+tW0WFi9wX+K2cxkQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.Binder": "6.0.0", - "Microsoft.Extensions.Configuration.CommandLine": "6.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "6.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "6.0.0", - "Microsoft.Extensions.Configuration.Json": "6.0.0", - "Microsoft.Extensions.Configuration.UserSecrets": "6.0.0", - "Microsoft.Extensions.DependencyInjection": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Physical": "6.0.0", - "Microsoft.Extensions.Hosting.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Configuration": "6.0.0", - "Microsoft.Extensions.Logging.Console": "6.0.0", - "Microsoft.Extensions.Logging.Debug": "6.0.0", - "Microsoft.Extensions.Logging.EventLog": "6.0.0", - "Microsoft.Extensions.Logging.EventSource": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0" - } - }, - "Microsoft.Extensions.Hosting.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Logging": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "System.Diagnostics.DiagnosticSource": "6.0.0" - } + "resolved": "8.0.0", + "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==" }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA==" - }, - "Microsoft.Extensions.Logging.Configuration": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "ZDskjagmBAbv+K8rYW9VhjPplhbOE63xUD0DiuydZJwt15dRyoqicYklLd86zzeintUc7AptDkHn+YhhYkYo8A==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.Binder": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.Console": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "gsqKzOEdsvq28QiXFxagmn1oRB9GeI5GgYCkoybZtQA0IUb7QPwf1WmN3AwJeNIsadTvIFQCiVK0OVIgKfOBGg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging.Configuration": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "System.Text.Json": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.Debug": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "M9g/JixseSZATJE9tcMn9uzoD4+DbSglivFqVx8YkRJ7VVPmnvCEbOZ0AAaxsL1EKyI4cz07DXOOJExxNsUOHw==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.EventLog": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "rlo0RxlMd0WtLG3CHI0qOTp6fFn7MvQjlrCjucA31RqmiMFCZkF8CHNbe8O7tbBIyyoLGWB1he9CbaA5iyHthg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "System.Diagnostics.EventLog": "6.0.0" - } - }, - "Microsoft.Extensions.Logging.EventSource": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "BeDyyqt7nkm/nr+Gdk+L8n1tUT/u33VkbXAOesgYSNsxDM9hJ1NOBGoZfj9rCbeD2+9myElI6JOVVFmnzgeWQA==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Logging": "6.0.0", - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0", - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Json": "6.0.0" - } - }, - "Microsoft.Extensions.Options": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Options.ConfigurationExtensions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "bXWINbTn0vC0FYc9GaQTISbxhQLAMrvtbuvD9N6JelEaIS/Pr62wUCinrq5bf1WRBGczt1v4wDhxFtVFNcMdUQ==", + "resolved": "8.0.3", + "contentHash": "dL0QGToTxggRLMYY4ZYX5AMwBb+byQBd/5dMiZE07Nv73o6I5Are3C7eQTh7K2+A4ct0PVISSr7TZANbiNb2yQ==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.Binder": "6.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Options": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2" } }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } + "resolved": "8.0.0", + "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, "Microsoft.Identity.Client": { "type": "Transitive", - "resolved": "4.46.0", - "contentHash": "cqNAIELaUypwWvTwnC3MdsccaSpEpVR10WBQ7+e33iSkceeC1kum6aTEwe2m8z4ZdnzlvEMH+dBbXBHMLCy+fQ==", + "resolved": "4.71.1", + "contentHash": "SgvSBcMRvmEEyV10pcvxNVUbwYoShmj/9pxXFVr3AFjE26IUzuwYLtLgt58xkEnT0xJBjfObaXxcol3BMtmEAg==", "dependencies": { - "Microsoft.IdentityModel.Abstractions": "6.18.0" + "Microsoft.IdentityModel.Abstractions": "6.35.0", + "System.Diagnostics.DiagnosticSource": "6.0.1" } }, "Microsoft.Identity.Client.Extensions.Msal": { "type": "Transitive", - "resolved": "2.23.0", - "contentHash": "Q8K58FjUIVslHQlk+SIhFYjdy8B1A5Wt3GXxzLS7lnXXaSmbcGzk7d8haqLmR8z/DP99vpZC73SxMa83qSHcbQ==", + "resolved": "4.71.1", + "contentHash": "PGOHaoQhKBKnXy1kfW+Gu9/rxStKsqR+UZKeVv4XAsATdzmfj9y9kkUOftIjVFvxP3oh2Sk7v65ylS0K/qYADA==", "dependencies": { - "Microsoft.Identity.Client": "4.46.0", - "System.IO.FileSystem.AccessControl": "5.0.0", + "Microsoft.Identity.Client": "4.71.1", "System.Security.Cryptography.ProtectedData": "4.5.0" } }, "Microsoft.IdentityModel.Abstractions": { "type": "Transitive", - "resolved": "6.18.0", - "contentHash": "ItCO09JoIQr9sY0AumHRLJKToMKM4/jFcBsg3uhKBZZLX1KPxjed/mKrQzo9PXiarfC87rguvFWWg9C996sEqA==" - }, - "Microsoft.NETCore.Platforms": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" + "resolved": "6.35.0", + "contentHash": "xuR8E4Rd96M41CnUSCiOJ2DBh+z+zQSmyrYHdYhD6K4fXBcQGVnRCFQ0efROUYpP+p0zC1BLKr0JRpVuujTZSg==" }, "Microsoft.SourceLink.Common": { "type": "Transitive", @@ -456,97 +238,61 @@ }, "StyleCop.Analyzers.Unstable": { "type": "Transitive", - "resolved": "1.2.0.435", - "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" + "resolved": "1.2.0.556", + "contentHash": "zvn9Mqs/ox/83cpYPignI8hJEM2A93s2HkHs8HYMOAQW0PkampyoErAiIyKxgTLqbbad29HX/shv/6LGSjPJNQ==" }, - "System.CommandLine.NamingConventionBinder": { + "System.ClientModel": { "type": "Transitive", - "resolved": "2.0.0-beta4.22272.1", - "contentHash": "ux2eUA/syF+JtlpMDc/Lsd6PBIBuwjH3AvHnestoh5uD0WKT5b+wkQxDWVCqp9qgVjMBTLNhX19ZYFtenunt9A==", + "resolved": "1.4.1", + "contentHash": "MY7eFGKp+Hu7Ciub8wigQ0odGrkml4eTjUy8d5Bu2eGAVvm8Qskkq+YuXiiS5wMJGq7iSvqseV4skd5WxTUdDA==", "dependencies": { - "System.CommandLine": "2.0.0-beta4.22272.1" + "Microsoft.Extensions.Logging.Abstractions": "8.0.3", + "System.Memory.Data": "6.0.1" } }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==", + "resolved": "6.0.1", + "contentHash": "KiLYDu2k2J82Q9BJpWiuQqCkFjRBWVq4jDzKKWawVi9KWzyD0XG3cmfX0vqTQlL14Wi9EufJrbL0+KCLTbqWiQ==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, - "System.Diagnostics.EventLog": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "lcyUiXTsETK2ALsZrX+nWuHSIQeazhqPphLfaRxzdGaG93+0kELqpgEHtwWOlQe7+jSFnKwaCAgL4kjeZCQJnw==" - }, - "System.IO.FileSystem.AccessControl": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", - "dependencies": { - "System.Security.AccessControl": "5.0.0", - "System.Security.Principal.Windows": "5.0.0" - } - }, "System.Memory": { "type": "Transitive", - "resolved": "4.5.5", - "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" + "resolved": "4.6.3", + "contentHash": "qdcDOgnFZY40+Q9876JUHnlHu7bosOHX8XISRoH94fwk6hgaeQGSgfZd8srWRZNt5bV9ZW2TljcegDNxsf+96A==" }, "System.Memory.Data": { "type": "Transitive", - "resolved": "1.0.2", - "contentHash": "JGkzeqgBsiZwKJZ1IxPNsDFZDhUvuEdX8L8BDC8N3KOj+6zMcNU28CNN59TpZE/VJYy9cP+5M+sbxtWJx3/xtw==", - "dependencies": { - "System.Text.Encodings.Web": "4.7.2", - "System.Text.Json": "4.6.0" - } - }, - "System.Numerics.Vectors": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + "resolved": "6.0.1", + "contentHash": "yliDgLh9S9Mcy5hBIdZmX6yphYIW3NH+3HN1kV1m7V1e0s7LNTw/tHNjJP4U9nSMEgl3w1TzYv/KA1Tg9NYy6w==" }, "System.Runtime.CompilerServices.Unsafe": { "type": "Transitive", "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, - "System.Security.AccessControl": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "5.0.0", - "System.Security.Principal.Windows": "5.0.0" - } - }, "System.Security.Cryptography.ProtectedData": { "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "ehYW0m9ptxpGWvE4zgqongBVWpSDU/JCFD4K7krxkQwSz/sFQjEXCUqpvencjy6DYDbn7Ig09R8GFffu8TtneQ==" - }, - "System.Security.Principal.Windows": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" + "resolved": "4.5.0", + "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" }, "System.Text.Encodings.Web": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "OP6umVGxc0Z0MvZQBVigj4/U31Pw72ITihDWP9WiWDm+q5aoe0GaJivsfYGq53o6dxH7DcXWiCTl7+0o2CGdmg==", + "resolved": "6.0.0", + "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, "System.Text.Json": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "DaGSsVqKsn/ia6RG8frjwmJonfos0srquhw09TlT8KRw5I43E+4gs+/bZj4K0vShJ5H9imCuXupb4RmS+dBy3w==", + "resolved": "6.0.10", + "contentHash": "NSB0kDipxn2ychp88NXWfFRFlmi1bst/xynOutbnpEfRCT9JZkZ7KOmF/I/hNKo2dILiMGnqblm+j1sggdLB9g==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "7.0.0" + "System.Text.Encodings.Web": "6.0.0" } }, "System.Threading.Tasks.Extensions": { diff --git a/azure-pipelines.release.yml b/azure-pipelines.release.yml deleted file mode 100644 index 4706281..0000000 --- a/azure-pipelines.release.yml +++ /dev/null @@ -1,15 +0,0 @@ -trigger: none -pr: none - -resources: - repositories: - - repository: recommended_practices - type: github - name: endjin/Endjin.RecommendedPractices.AzureDevopsPipelines.GitHub - endpoint: endjin-github - -jobs: -- template: templates/tag.for.release.yml@recommended_practices - parameters: - vmImage: 'windows-latest' - service_connection_github: $(Endjin_Service_Connection_GitHub) \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index b00bf8a..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,24 +0,0 @@ -trigger: - branches: - include: - - main - - feature/* - tags: - include: - - '*' - -resources: - repositories: - - repository: recommended_practices - type: github - name: endjin/Endjin.RecommendedPractices.AzureDevopsPipelines.GitHub - endpoint: endjin-github - -jobs: -- template: templates/build.and.release.scripted.yml@recommended_practices - parameters: - vmImage: 'ubuntu-latest' - service_connection_nuget_org: $(Endjin_Service_Connection_NuGet_Org) - service_connection_github: $(Endjin_Service_Connection_GitHub) - solution_to_build: $(Endjin_Solution_To_Build) - netSdkVersion: '6.x' \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 8f8958c..bb95a74 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,12 +1,13 @@ +#Requires -Version 7 <# .SYNOPSIS Runs a .NET flavoured build process. .DESCRIPTION - This script was scaffolded using a template from the Endjin.RecommendedPractices.Build PowerShell module. - It uses the InvokeBuild module to orchestrate an opinonated software build process for .NET solutions. + This script was scaffolded using a template from the ZeroFailed project. + It uses the InvokeBuild module to orchestrate an opinionated software build process for .NET solutions. .EXAMPLE PS C:\> ./build.ps1 - Downloads any missing module dependencies (Endjin.RecommendedPractices.Build & InvokeBuild) and executes + Downloads any missing module dependencies (ZeroFailed & InvokeBuild) and executes the build process. .PARAMETER Tasks Optionally override the default task executed as the entry-point of the build. @@ -26,14 +27,12 @@ The logging verbosity. .PARAMETER Clean When true, the .NET solution will be cleaned and all output/intermediate folders deleted. -.PARAMETER BuildModulePath - The path to import the Endjin.RecommendedPractices.Build module from. This is useful when - testing pre-release versions of the Endjin.RecommendedPractices.Build that are not yet - available in the PowerShell Gallery. -.PARAMETER BuildModuleVersion - The version of the Endjin.RecommendedPractices.Build module to import. This is useful when - testing pre-release versions of the Endjin.RecommendedPractices.Build that are not yet - available in the PowerShell Gallery. +.PARAMETER ZfModulePath + The path to import the ZeroFailed module from. This is useful when testing pre-release + versions of ZeroFailed that are not yet available in the PowerShell Gallery. +.PARAMETER ZfModuleVersion + The version of the ZeroFailed module to import. This is useful when testing pre-release + versions of ZeroFailed that are not yet available in the PowerShell Gallery. .PARAMETER InvokeBuildModuleVersion The version of the InvokeBuild module to be used. #> @@ -68,111 +67,55 @@ param ( [switch] $Clean, [Parameter()] - [string] $BuildModulePath, + [string] $ZfModulePath, [Parameter()] - [version] $BuildModuleVersion = "1.5.11", + [string] $ZfModuleVersion = "1.0.5", [Parameter()] - [version] $InvokeBuildModuleVersion = "5.10.3" + [version] $InvokeBuildModuleVersion = "5.12.1" ) - -$ErrorActionPreference = $ErrorActionPreference ? $ErrorActionPreference : 'Stop' -$InformationPreference = 'Continue' - +$ErrorActionPreference = 'Stop' $here = Split-Path -Parent $PSCommandPath #region InvokeBuild setup -if (!(Get-Module -ListAvailable InvokeBuild)) { - Install-Module InvokeBuild -RequiredVersion $InvokeBuildModuleVersion -Scope CurrentUser -Force -Repository PSGallery -} -Import-Module InvokeBuild # This handles calling the build engine when this file is run like a normal PowerShell script # (i.e. avoids the need to have another script to setup the InvokeBuild environment and issue the 'Invoke-Build' command ) if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { + Install-PSResource InvokeBuild -Version $InvokeBuildModuleVersion -Scope CurrentUser -TrustRepository -Verbose:$false | Out-Null try { Invoke-Build $Tasks $MyInvocation.MyCommand.Path @PSBoundParameters } catch { - $_.ScriptStackTrace - throw + Write-Host -f Yellow "`n`n***`n*** Build Failure Summary - check previous logs for more details`n***" + Write-Host -f Yellow $_.Exception.Message + Write-Host -f Yellow $_.ScriptStackTrace + exit 1 } return } #endregion -#region Import shared tasks and initialise build framework -if (!($BuildModulePath)) { - if (!(Get-Module -ListAvailable Endjin.RecommendedPractices.Build | ? { $_.Version -eq $BuildModuleVersion })) { - Write-Information "Installing 'Endjin.RecommendedPractices.Build' module..." - Install-Module Endjin.RecommendedPractices.Build -RequiredVersion $BuildModuleVersion -Scope CurrentUser -Force -Repository PSGallery - } - $BuildModulePath = "Endjin.RecommendedPractices.Build" +#region Initialise build framework +$splat = @{ Force = $true; Verbose = $false} +Import-Module Microsoft.PowerShell.PSResourceGet +if (!($ZfModulePath)) { + Install-PSResource ZeroFailed -Version $ZfModuleVersion -Scope CurrentUser -TrustRepository | Out-Null + $ZfModulePath = "ZeroFailed" + $splat.Add("RequiredVersion", ($ZfModuleVersion -split '-')[0]) } else { - Write-Information "BuildModulePath: $BuildModulePath" + Write-Host "ZfModulePath: $ZfModulePath" } -Import-Module $BuildModulePath -RequiredVersion $BuildModuleVersion -Force - -# Load the build process & tasks -. Endjin.RecommendedPractices.Build.tasks +$splat.Add("Name", $ZfModulePath) +# Ensure only 1 version of the module is loaded +Get-Module ZeroFailed | Remove-Module +Import-Module @splat +$ver = "{0} {1}" -f (Get-Module ZeroFailed).Version, (Get-Module ZeroFailed).PrivateData.PsData.PreRelease +Write-Host "Using ZeroFailed module version: $ver" #endregion +$PSModuleAutoloadingPreference = 'none' -# -# Build process control options -# -$SkipInit = $false -$SkipVersion = $false -$SkipBuild = $false -$CleanBuild = $Clean -$SkipTest = $false -$SkipTestReport = $false -$SkipAnalysis = $false -$SkipPackage = $false -$SkipPublish = $false - - -# -# Build process configuration -# -$SolutionToBuild = (Resolve-Path (Join-Path $here ".\Solutions\AzAppConfigToUserSecrets.sln")).Path -$ProjectsToPublish = @( - # "Solutions/MySolution/MyWebSite/MyWebSite.csproj" -) -$NuSpecFilesToPackage = @( - # "Solutions/MySolution/MyProject/MyProject.nuspec" -) - -# -# Specify files to exclude from code coverage -# This option is for excluding generated code -# - Use file path or directory path with globbing (e.g dir1/*.cs) -# - Use single or multiple paths (separated by comma) (e.g. **/dir1/class1.cs,**/dir2/*.cs,**/dir3/**/*.cs) -# -$ExcludeFilesFromCodeCoverage = "" - -# Synopsis: Build, Test and Package -task . FullBuild - - -# build extensibility tasks -task RunFirst {} -task PreInit {} -task PostInit {} -task PreVersion {} -task PostVersion {} -task PreBuild {} -task PostBuild {} -task PreTest {} -task PostTest {} -task PreTestReport {} -task PostTestReport {} -task PreAnalysis {} -task PostAnalysis {} -task PrePackage {} -task PostPackage {} -task PrePublish {} -task PostPublish {} -task RunLast {} - +# Load the build configuration +. $here/.zf/config.ps1