diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 9fd703d..7dafabe 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,14 +3,14 @@
"isRoot": true,
"tools": {
"fixie.console": {
- "version": "3.4.0",
+ "version": "4.1.0",
"commands": [
"fixie"
],
"rollForward": false
},
"dotnet-outdated-tool": {
- "version": "4.6.1",
+ "version": "4.6.8",
"commands": [
"dotnet-outdated"
],
diff --git a/.editorconfig b/.editorconfig
index 573ba3c..4de8261 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,8 +8,9 @@ root = true
#### Core EditorConfig Options ####
# So code cleanup will not run on save.
-[_Imports.cs]
+[_*.cs]
generated_code = true
+dotnet_diagnostic.TWA001.severity = none
[*.csproj]
generated_code = true
@@ -255,6 +256,9 @@ dotnet_naming_style.local_function_style.capitalization = pascal_case
#### Analyizer settings ####
dotnet_code_quality.null_check_validation_methods = NotNull
+# TWA001: Enforce kebab-case naming convention
+dotnet_diagnostic.TWA001.severity = warning
+
# CA1062: Validate arguments of public methods
# TODO: Turn this back on when figure out how to get Dawn.Guard to not trigger it.
dotnet_diagnostic.CA1062.severity = silent
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
deleted file mode 100644
index c855e14..0000000
--- a/.github/workflows/ci-build.yml
+++ /dev/null
@@ -1,54 +0,0 @@
-name: Build and Test
-
-on:
- pull_request:
- workflow_dispatch:
-
-env:
- DOTNET_NOLOGO: true # Disable the .NET logo in the console output
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true # Disable the .NET first time experience to skip caching NuGet packages and speed up the build
- DOTNET_CLI_TELEMETRY_OPTOUT: true
- NUGET_AUTH_TOKEN: ${{secrets.PUBLISH_TO_NUGET_ORG}} # <-- This is the token for the GitHub account you want to use.
-
-jobs:
- build-and-test:
- runs-on: ubuntu-latest
- strategy:
- matrix:
- project:
- - name: TimeWarp.OptionsValidation
- path: Source/TimeWarp.OptionsValidation/
- testPath: Tests/TimeWarp.OptionsValidation.Tests/
-
- steps:
- - name: Print Job Info
- run: |
- echo "🎉 Job triggered by a ${{ github.event_name }} event."
- echo "🐧 Running on a ${{ runner.os }} server hosted by GitHub."
- echo "🔎 Branch name: ${{ github.ref }}, repository: ${{ github.repository }}."
-
- - name: Check out repository code
- uses: actions/checkout@v3
-
- - name: Setup .NET
- uses: actions/setup-dotnet@v2
- with:
- dotnet-version: 8.0.x
-
- - name: Build ${{ matrix.project.name }}
- run: |
- cd ${{ matrix.project.path }}
- dotnet build --configuration Debug
- shell: pwsh
-
- - name: Test ${{ matrix.project.name }}
- run: |
- cd ${{ matrix.project.testPath }}
- dotnet tool restore
- dotnet restore
- dotnet fixie --configuration Debug
- shell: pwsh
-
- - name: Print Job Status
- run: |
- echo "🍏 Job status: ${{ job.status }}."
diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml
new file mode 100644
index 0000000..f62ef4f
--- /dev/null
+++ b/.github/workflows/ci-cd.yml
@@ -0,0 +1,82 @@
+name: NuGet Publish
+
+on:
+ push:
+ branches:
+ - master
+ paths:
+ - 'source/**'
+ - 'tests/**'
+ - '.github/workflows/**'
+ - 'Directory.Build.props'
+ - 'Directory.Packages.props'
+ pull_request:
+ branches:
+ - master
+ paths:
+ - 'source/**'
+ - 'tests/**'
+ - '.github/workflows/**'
+ - 'Directory.Build.props'
+ - 'Directory.Packages.props'
+ release:
+ types: [published] # Triggered when a release is published via GitHub Releases UI or gh CLI
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Version to publish (e.g., 1.0.0-beta.3)'
+ required: false
+ type: string
+
+jobs:
+ build-and-publish:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Create artifacts directory
+ run: mkdir -p artifacts/packages
+
+ - name: Build
+ run: dotnet build --configuration Release
+
+ - name: Test
+ run: |
+ cd tests/timewarp-options-validation-tests
+ dotnet tool restore
+ dotnet restore
+ dotnet fixie --configuration Release
+
+ - name: Publish to NuGet.org (Releases only)
+ if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.version != '')
+ run: |
+ # Get version from either release tag or manual input
+ if [ "${{ github.event_name }}" == "release" ]; then
+ VERSION="${{ github.event.release.tag_name }}"
+ VERSION="${VERSION#v}" # Remove 'v' prefix if present
+ else
+ VERSION="${{ github.event.inputs.version }}"
+ fi
+
+ echo "Publishing version: $VERSION"
+
+ dotnet nuget push artifacts/packages/TimeWarp.OptionsValidation.$VERSION.nupkg \
+ --api-key ${{ secrets.PUBLISH_TO_NUGET_ORG }} \
+ --source https://api.nuget.org/v3/index.json \
+ --skip-duplicate
+ env:
+ DOTNET_NUGET_SIGNATURE_VERIFICATION: false
+
+ - name: Upload Artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: Packages-${{ github.run_number }}
+ path: artifacts/packages/*.nupkg
diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml
deleted file mode 100644
index b7df503..0000000
--- a/.github/workflows/release-build.yml
+++ /dev/null
@@ -1,108 +0,0 @@
-name: Build and Deploy
-
-on:
- push:
- branches:
- - master
- workflow_dispatch:
-
-env:
- DOTNET_NOLOGO: true # Disable the .NET logo in the console output
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true # Disable the .NET first time experience to skip caching NuGet packages and speed up the build
- DOTNET_CLI_TELEMETRY_OPTOUT: true
- NUGET_AUTH_TOKEN: ${{ secrets.PUBLISH_TO_NUGET_ORG }} # <-- This is the token for the GitHub account you want to use.
-
-defaults:
- run:
- shell: pwsh
-
-jobs:
- build-and-deploy:
- runs-on: ubuntu-latest
-
- steps:
- - name: Print Job Info
- run: |
- echo "🎉 Job triggered by a ${{ github.event_name }} event."
- echo "🐧 Running on a ${{ runner.os }} server hosted by GitHub."
- echo "🔎 Branch name: ${{ github.ref }}, repository: ${{ github.repository }}."
-
- - name: Check out repository code
- uses: actions/checkout@v3
-
- - name: Setup .NET
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: 8.0.x
-
- - name: Build TimeWarp.OptionsValidation
- run: |
- cd Source/TimeWarp.OptionsValidation/
- dotnet build --configuration Debug
-
- - name: Publish TimeWarp.OptionsValidation
- run: |
- cd Source/TimeWarp.OptionsValidation/bin/Packages
- dotnet nuget push *.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.PUBLISH_TO_NUGET_ORG }}
-
- - name: Verify Directory.Build.props
- run: |
- if (Test-Path -Path "Directory.Build.props") {
- Get-Content -Path "Directory.Build.props"
- } else {
- Write-Error "Directory.Build.props not found at the expected path."
- }
-
- - name: Tag commit with version
- run: |
- git config --local user.email "action@github.com"
- git config --local user.name "GitHub Action"
- $version = (Select-String -Path "Directory.Build.props" -Pattern '(.*?)').Matches.Groups[1].Value
- git tag -a "$version" -m "Release $version"
- git push origin "$version"
-
- - name: Check if version is not a pre-release
- id: check_pre_release
- run: |
- $version = (Select-String -Path "Directory.Build.props" -Pattern '(.*?)').Matches.Groups[1].Value
- $isPreRelease = $version -match '-(alpha|beta)'
- echo "IsPreRelease=$isPreRelease"
- # Setting output that indicates whether it's a pre-release version
- echo "::set-output name=IS_PRE_RELEASE::$isPreRelease"
-
- - name: Generate Release Notes
- id: generate_release_notes
- uses: release-drafter/release-drafter@v5
- with:
- version: ${{ steps.tag_commit.outputs.VERSION }}
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Save Release Notes to File
- if: steps.check_pre_release.outputs.IS_PRE_RELEASE == 'False'
- run: |
- $releaseNotes = "${{ steps.generate_release_notes.outputs.body }}"
- $filePath = "Documentation/ReleaseNotes/Release_${{ steps.tag_commit.outputs.VERSION }}.md"
- if (-not (Test-Path -Path "Documentation/ReleaseNotes")) {
- New-Item -ItemType Directory -Path "Documentation/ReleaseNotes" -Force
- }
- Set-Content -Path $filePath -Value $releaseNotes
- git add $filePath
- git commit -m "Add release notes for version ${{ steps.tag_commit.outputs.VERSION }}"
- git push origin master
-
- - name: Create GitHub Release
- if: steps.check_pre_release.outputs.IS_PRE_RELEASE == 'False'
- uses: actions/create-release@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: ${{ steps.tag_commit.outputs.VERSION }}
- release_name: Release ${{ steps.tag_commit.outputs.VERSION }}
- draft: true
- prerelease: false
- body: ${{ steps.generate_release_notes.outputs.body }}
-
- - name: Print Job Status
- run: |
- echo "🍏 Job status: ${{ job.status }}."
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..b72137c
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,22 @@
+{
+ "workbench.colorCustomizations": {
+ "activityBar.activeBackground": "#f58b87",
+ "activityBar.background": "#f58b87",
+ "activityBar.foreground": "#15202b",
+ "activityBar.inactiveForeground": "#15202b99",
+ "activityBarBadge.background": "#e2fde3",
+ "activityBarBadge.foreground": "#15202b",
+ "commandCenter.border": "#15202b99",
+ "sash.hoverBorder": "#f58b87",
+ "statusBar.background": "#f15e58",
+ "statusBar.foreground": "#15202b",
+ "statusBarItem.hoverBackground": "#ed3129",
+ "statusBarItem.remoteBackground": "#f15e58",
+ "statusBarItem.remoteForeground": "#15202b",
+ "titleBar.activeBackground": "#f15e58",
+ "titleBar.activeForeground": "#15202b",
+ "titleBar.inactiveBackground": "#f15e5899",
+ "titleBar.inactiveForeground": "#15202b99"
+ },
+ "peacock.remoteColor": "#F15E58"
+}
\ No newline at end of file
diff --git a/CodeMaid.config b/CodeMaid.config
deleted file mode 100644
index 810ab01..0000000
--- a/CodeMaid.config
+++ /dev/null
@@ -1,71 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- False
-
-
- False
-
-
- True
-
-
- 1
-
-
- \.Designer\.cs$||\.Designer\.vb$||\.resx$||\.min\.css$||\.min\.js$||\\lib\\
-
-
- False
-
-
- False
-
-
- 1
-
-
- Constructors||3||Constructors
-
-
- Properties||2||Properties
-
-
- Enums||7||Enums
-
-
- Destructors||4||Destructors
-
-
- Delegates||5||Delegates
-
-
- Fields||1||Fields
-
-
- Interfaces||8||Interfaces
-
-
- Events||6||Events
-
-
- True
-
-
- True
-
-
- True
-
-
-
-
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index bd23c15..2695885 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,41 +1,82 @@
-
-
-
- Steven T. Cramer
- TimeWarp Enterprises
- TimeWarp.OptionsValidation
- TimeWarp.OptionsValidation uses fluent validation to check your configuration settings.
- git
- https://github.com/TimeWarpEngineering/timewarp-options-validation.git
- https://timewarpengineering.github.io/timewarp-options-validation/
- TimeWarp; Options Validation;OptionsValidation
- 1.0.0-beta.2+8.0.205
- Unlicense
- Logo.png
- README.md
+
+
+
+ timewarp-options-validation
+ $(RepositoryRoot)timewarp-options-validation.slnx
+ $(MSBuildThisFileDirectory)
+ $(RepositoryRoot)source/
+ $(RepositoryRoot)tests/
+ $(RepositoryRoot)Documentation/
+ $(RepositoryRoot)artifacts/
+ $(ArtifactsDirectory)packages/
-
-
- true
- true
- true
- true
- enable
- preview
+
+
+
+ $(PackagesDirectory)
+
+
true
+
+
+ true
+
+
+
+
+ net10.0
+ enable
enable
- net8.0
+ latest
+ false
+ true
+
+
+
+
+
true
+ 5
+ true
+ true
+ All
+ latest-all
+
+
+ true
+ true
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(NoWarn);CA1014;CA1031;CA1052;CA1515;CA1707;CA1724;CA1812;CA1848;CA1852;CA2007;RCS1102;IL2026;IL2067;IL2070;IL2075;IL3050;IL2104;IL3053
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
index d8c418f..0731f86 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,20 +1,43 @@
-
+
+
+ true
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Documentation/releases.md b/Documentation/releases.md
deleted file mode 100644
index e69de29..0000000
diff --git a/NuGet.config b/NuGet.config
index 1abb5cd..80f5bd7 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,14 +4,4 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/README.md b/README.md
deleted file mode 100644
index 7897c7e..0000000
--- a/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-[](https://dotnet.microsoft.com)
-[](https://github.com/TimeWarpEngineering/timewarp-options-validation)
-[](https://discord.gg/7F4bS2T)
-[](https://github.com/TimeWarpEngineering/timewarp-options-validation/actions)
-[](https://www.nuget.org/packages/TimeWarp.OptionsValidation/)
-[](https://www.nuget.org/packages/TimeWarp.OptionsValidation/)
-[](https://github.com/TimeWarpEngineering/timewarp-options-validation/issues)
-[](https://github.com/TimeWarpEngineering/timewarp-options-validation)
-[](https://github.com/TimeWarpEngineering/timewarp-options-validation/issues)
-[](https://twitter.com/intent/tweet?url=https://github.com/TimeWarpEngineering/timewarp-options-validation)
-
-[](https://twitter.com/intent/follow?screen_name=StevenTCramer)
-[](https://twitter.com/intent/follow?screen_name=TheFreezeTeam1)
-
-# TimeWarp.OptionsValidation
-
-
-
-TimeWarp.OptionsValidation uses fluent validation to check your configuration settings.
-
-## Give a Star! :star:
-
-If you like or are using this project please give it a star. Thank you!
-
-## Getting started
-
-To quickly get started I recommend reviewing the samples in this repo.
-
-## Installation
-
-```console
-dotnet add package TimeWarp.OptionsValidation
-```
-
-You can see the latest NuGet packages from the official [TimeWarp NuGet page](https://www.nuget.org/profiles/TimeWarp.Enterprises).
-
-* [TimeWarp.OptionsValidation](https://www.nuget.org/packages/TimeWarp.OptionsValidation/) [](https://www.nuget.org/packages/TimeWarp.OptionsValidation/)
-
-## Releases
-
-See the [Release Notes](./documentation/releases.md)
-## Unlicense
-
-[](https://unlicense.org)
-
-## Contributing
-
-Time is of the essence. Before developing a Pull Request I recommend opening a [discussion](https://github.com/TimeWarpEngineering/timewarp-options-validation/discussions).
-
-Please feel free to make suggestions and help out with the [documentation](https://timewarpengineering.github.io/timewarp-options-validation/).
-Please refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files.
-
-## Contact
-
-Sometimes the github notifications get lost in the shuffle. If you file an [issue](https://github.com/TimeWarpEngineering/timewarp-options-validation/issues) and don't get a response in a timely manner feel free to ping on our [Discord server](https://discord.gg/A55JARGKKP).
-
-[](https://discord.gg/7F4bS2T)
diff --git a/Source/TimeWarp.OptionsValidation/Configuration/SectionNameAttribute.cs b/Source/TimeWarp.OptionsValidation/Configuration/SectionNameAttribute.cs
deleted file mode 100644
index 8b7f5a8..0000000
--- a/Source/TimeWarp.OptionsValidation/Configuration/SectionNameAttribute.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace TimeWarp.OptionsValidation;
-
-///
-/// The section name in appsettings.json to which the class should be mapped
-///
-[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
-public class SectionNameAttribute : Attribute
-{
- public string SectionName { get; set; }
- public SectionNameAttribute(string aSectionName)
- {
- this.SectionName = aSectionName;
- }
-}
diff --git a/Source/TimeWarp.OptionsValidation/Extensions/ServiceCollectionExtensions.cs b/Source/TimeWarp.OptionsValidation/Extensions/ServiceCollectionExtensions.cs
deleted file mode 100644
index acd2aa3..0000000
--- a/Source/TimeWarp.OptionsValidation/Extensions/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-namespace Microsoft.Extensions.DependencyInjection;
-
-public static class ServiceCollectionExtensions
-{
- public static IServiceCollection ConfigureOptions
- (
- this IServiceCollection aServiceCollection,
- IConfiguration aConfiguration
- )
- where TOptions : class
- where TOptionsValidator : AbstractValidator
- {
- Type type = typeof(TOptions);
- var sectionNameAttribute = (SectionNameAttribute?)type.GetCustomAttributes(typeof(SectionNameAttribute), false).FirstOrDefault();
- string sectionName = sectionNameAttribute?.SectionName ?? type.Name;
- IConfigurationSection configurationSection = aConfiguration.GetSection(sectionName);
-
- aServiceCollection.Configure(configurationSection);
- return RegisterOptionsValidator(aServiceCollection);
- }
-
- public static IServiceCollection ConfigureOptions(this IServiceCollection aServiceCollection, Action aOptionsAction)
- where TOptions : class
- where TOptionsValidator : AbstractValidator
- {
- aServiceCollection.Configure(aOptionsAction);
- return RegisterOptionsValidator(aServiceCollection);
- }
-
- private static IServiceCollection RegisterOptionsValidator
- (IServiceCollection aServiceCollection)
- where TOptions : class
- where TOptionsValidator : AbstractValidator
- {
- aServiceCollection.TryAddSingleton();
-
- aServiceCollection.TryAddEnumerable
- (
- ServiceDescriptor.Singleton
- <
- IValidateOptions,
- OptionsValidation
- >()
- );
-
- return aServiceCollection;
- }
-}
diff --git a/Source/TimeWarp.OptionsValidation/Extensions/ServiceProviderExtensions.cs b/Source/TimeWarp.OptionsValidation/Extensions/ServiceProviderExtensions.cs
deleted file mode 100644
index 2ae7f25..0000000
--- a/Source/TimeWarp.OptionsValidation/Extensions/ServiceProviderExtensions.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-namespace Microsoft.Extensions.DependencyInjection;
-
-using Logging;
-
-///
-/// Run Validation on all the IOptions that have validation
-/// This will iterate through all the IConfigureOptions in the IServiceCollection
-/// Then it will access each of those which will trigger the validation.
-///
-public static class ServiceProviderExtensions
-{
- public static void ValidateOptions
- (
- this IServiceProvider serviceProvider,
- IServiceCollection serviceCollection,
- ILogger logger
- )
- {
- using IServiceScope scope = serviceProvider.CreateScope();
- IServiceProvider scopedProvider = scope.ServiceProvider;
- ValidateOptionsInternal(scopedProvider, serviceCollection, logger);
- }
-
- private static void ValidateOptionsInternal
- (
- this IServiceProvider serviceProvider,
- IServiceCollection serviceCollection,
- ILogger logger
- )
- {
- IEnumerable optionTypes =
- serviceCollection
- .Where
- (
- serviceDescriptor =>
- serviceDescriptor.ServiceType.IsGenericType &&
- serviceDescriptor.ServiceType.GetGenericTypeDefinition() == typeof(IConfigureOptions<>)
- )
- .Select
- (
- serviceDescriptor => serviceDescriptor.ServiceType.GetGenericArguments()[0]
- ).Distinct();
-
- Func? originalDisplayNameResolver = ValidatorOptions.Global.DisplayNameResolver;
-
- ValidatorOptions.Global.DisplayNameResolver =
- (type, memberInfo, _) =>
- type != null && memberInfo != null ? $"{type.Name}:{memberInfo.Name}" : null;
-
-
- foreach (Type optionType in optionTypes)
- {
- try
- {
- Type optionsAccessorType = typeof(IOptions<>).MakeGenericType(new Type[] { optionType });
- object? optionsAccessor = serviceProvider.GetService(optionsAccessorType);
- // Accessing the value triggers the validation.
- object? _ = optionsAccessor?.GetType().GetProperty(nameof(IOptions