From 216acc7ee5fd3b86982d03498ffa2b806b3feb2a Mon Sep 17 00:00:00 2001 From: Vladimir Seldemirov Date: Tue, 22 Oct 2024 13:28:14 +0400 Subject: [PATCH] Add BitzArt.CoreExtensions (#12) * Add BitzArt.CoreExtensions * Set TargetFrameworks * Add ImplicitUsings * Update TaskExtensions --- .github/workflows/Publish CoreExtensions.yml | 37 ++++++++++++++ .github/workflows/Tests.yml | 30 +++++++++++ Miscellaneous.sln | 18 ++++++- .../BitzArt.CoreExtensions.csproj | 19 +++++++ .../Enums/ComparisonType.cs | 37 ++++++++++++++ .../Enums/OrderDirection.cs | 39 ++++++++++++++ .../Extensions/TaskExtensions.cs | 51 +++++++++++++++++++ .../BitzArt.CoreExtensions.Tests.csproj | 27 ++++++++++ .../TaskExtensionsTests.cs | 44 ++++++++++++++++ 9 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/Publish CoreExtensions.yml create mode 100644 .github/workflows/Tests.yml create mode 100644 src/Misc/BitzArt.CoreExtensions/BitzArt.CoreExtensions.csproj create mode 100644 src/Misc/BitzArt.CoreExtensions/Enums/ComparisonType.cs create mode 100644 src/Misc/BitzArt.CoreExtensions/Enums/OrderDirection.cs create mode 100644 src/Misc/BitzArt.CoreExtensions/Extensions/TaskExtensions.cs create mode 100644 tests/Misc/BitzArt.CoreExtensions.Tests/BitzArt.CoreExtensions.Tests.csproj create mode 100644 tests/Misc/BitzArt.CoreExtensions.Tests/TaskExtensionsTests.cs diff --git a/.github/workflows/Publish CoreExtensions.yml b/.github/workflows/Publish CoreExtensions.yml new file mode 100644 index 0000000..13d2411 --- /dev/null +++ b/.github/workflows/Publish CoreExtensions.yml @@ -0,0 +1,37 @@ +name: Release CoreExtensions package + +on: + repository_dispatch: + push: + tags: + - "CoreExtensions-v[0-9]+.[0-9]+.[0-9]+*" + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NUGET_APIKEY: ${{ secrets.NUGET_APIKEY}} + +jobs: + + Release: + name: 'Release CoreExtensions package' + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v2 + + - name: Verify commit + run: | + git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* + git branch --remote --contains | grep origin/main + + - name: Set version + run: echo "VERSION=${GITHUB_REF/refs\/tags\/CoreExtensions-v/}" >> $GITHUB_ENV + + - name: Build + run: | + dotnet build src/Misc/BitzArt.CoreExtensions/BitzArt.CoreExtensions.csproj --configuration Release /p:Version=${VERSION} + dotnet pack src/Misc/BitzArt.CoreExtensions/BitzArt.CoreExtensions.csproj --configuration Release /p:Version=${VERSION} --no-build --output . + + - name: Push + run: dotnet nuget push BitzArt.CoreExtensions.${VERSION}.nupkg --source https://api.nuget.org/v3/index.json --api-key ${NUGET_APIKEY} diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml new file mode 100644 index 0000000..14ed3c6 --- /dev/null +++ b/.github/workflows/Tests.yml @@ -0,0 +1,30 @@ +name: Tests + +on: + push: + branches: + - main + tags-ignore: + - '*' + paths: + - "src/**" + - "tests/**" + - "Miscellaneous.sln" + - ".github/workflows/Tests.yml" + +jobs: + tests: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Install dependencies + run: dotnet restore + + - name: Build + run: dotnet build --configuration Release --no-restore + + - name: Test + run: dotnet test --no-restore --verbosity normal \ No newline at end of file diff --git a/Miscellaneous.sln b/Miscellaneous.sln index 434092a..6307627 100644 --- a/Miscellaneous.sln +++ b/Miscellaneous.sln @@ -13,12 +13,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{2DA8 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{9545DA65-B29C-4A40-8010-3E339D138EE9}" ProjectSection(SolutionItems) = preProject + .github\workflows\Publish CoreExtensions.yml = .github\workflows\Publish CoreExtensions.yml .github\workflows\Publish EnumToMemberValue.yml = .github\workflows\Publish EnumToMemberValue.yml .github\workflows\Publish FluentValidation.Extensions.yml = .github\workflows\Publish FluentValidation.Extensions.yml .github\workflows\Publish Json.TypedObjects.yml = .github\workflows\Publish Json.TypedObjects.yml .github\workflows\Publish LinqExtensions.yml = .github\workflows\Publish LinqExtensions.yml .github\workflows\Publish MassTransit.ConsumerBase.yml = .github\workflows\Publish MassTransit.ConsumerBase.yml .github\workflows\Publish Patcher.yml = .github\workflows\Publish Patcher.yml + .github\workflows\Tests.yml = .github\workflows\Tests.yml EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitzArt.MassTransit.ConsumerBase", "src\MassTransit\BitzArt.MassTransit.ConsumerBase\BitzArt.MassTransit.ConsumerBase.csproj", "{1A828274-0B29-4892-8525-D9E3F79471EC}" @@ -55,7 +57,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitzArt.LinqExtensions.Batc EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitzArt.LinqExtensions.Batching.Tests", "tests\BitzArt.LinqExtensions.Batching.Tests\BitzArt.LinqExtensions.Batching.Tests.csproj", "{6DBA7894-9852-4DF1-B9E0-09D60D311F6B}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{629938AD-8A1E-49C0-ABFB-724E564B0CCB}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sln", "sln", "{629938AD-8A1E-49C0-ABFB-724E564B0CCB}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig EndProjectSection @@ -76,6 +78,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linq", "Linq", "{BFE4986F-C EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{A5E6C844-8858-442E-8EAB-2CFD2E59B9EB}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitzArt.CoreExtensions", "src\Misc\BitzArt.CoreExtensions\BitzArt.CoreExtensions.csproj", "{350EF47C-407B-4509-AE6C-A86F17ED0C80}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BitzArt.CoreExtensions.Tests", "tests\Misc\BitzArt.CoreExtensions.Tests\BitzArt.CoreExtensions.Tests.csproj", "{039255F7-8BFF-4A5E-ABB6-602AF5F14AA5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -142,6 +148,14 @@ Global {8F88487B-C78F-4695-B4F3-BF59CCDF6DF0}.Debug|Any CPU.Build.0 = Debug|Any CPU {8F88487B-C78F-4695-B4F3-BF59CCDF6DF0}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F88487B-C78F-4695-B4F3-BF59CCDF6DF0}.Release|Any CPU.Build.0 = Release|Any CPU + {350EF47C-407B-4509-AE6C-A86F17ED0C80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {350EF47C-407B-4509-AE6C-A86F17ED0C80}.Debug|Any CPU.Build.0 = Debug|Any CPU + {350EF47C-407B-4509-AE6C-A86F17ED0C80}.Release|Any CPU.ActiveCfg = Release|Any CPU + {350EF47C-407B-4509-AE6C-A86F17ED0C80}.Release|Any CPU.Build.0 = Release|Any CPU + {039255F7-8BFF-4A5E-ABB6-602AF5F14AA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {039255F7-8BFF-4A5E-ABB6-602AF5F14AA5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {039255F7-8BFF-4A5E-ABB6-602AF5F14AA5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {039255F7-8BFF-4A5E-ABB6-602AF5F14AA5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -174,6 +188,8 @@ Global {8F88487B-C78F-4695-B4F3-BF59CCDF6DF0} = {23E7F528-746A-4A42-8FB3-F89088395933} {BFE4986F-CD69-4E42-8C6E-F8EE35491BBF} = {6C59FADC-BAEA-46B7-A69F-DC2AA0A124D6} {A5E6C844-8858-442E-8EAB-2CFD2E59B9EB} = {6C59FADC-BAEA-46B7-A69F-DC2AA0A124D6} + {350EF47C-407B-4509-AE6C-A86F17ED0C80} = {A053045B-CB06-473C-A04E-D54A519B6BBD} + {039255F7-8BFF-4A5E-ABB6-602AF5F14AA5} = {A5E6C844-8858-442E-8EAB-2CFD2E59B9EB} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {49BCA0AC-45AF-4DE6-B691-30A0F2959200} diff --git a/src/Misc/BitzArt.CoreExtensions/BitzArt.CoreExtensions.csproj b/src/Misc/BitzArt.CoreExtensions/BitzArt.CoreExtensions.csproj new file mode 100644 index 0000000..28df302 --- /dev/null +++ b/src/Misc/BitzArt.CoreExtensions/BitzArt.CoreExtensions.csproj @@ -0,0 +1,19 @@ + + + + net6.0;net7.0;net8.0 + enable + BitzArt + enable + true + + BitzArt.CoreExtensions + BitzArt + Base Class Library Extensions + MIT + git + https://github.com/BitzArt/Miscellaneous + https://github.com/BitzArt/Miscellaneous + + + diff --git a/src/Misc/BitzArt.CoreExtensions/Enums/ComparisonType.cs b/src/Misc/BitzArt.CoreExtensions/Enums/ComparisonType.cs new file mode 100644 index 0000000..a5108d1 --- /dev/null +++ b/src/Misc/BitzArt.CoreExtensions/Enums/ComparisonType.cs @@ -0,0 +1,37 @@ +namespace BitzArt; + +/// +/// Condition for comparing values. +/// +public enum ComparisonType : byte +{ + /// + /// Represents an equality condition. + /// + Equal = 0, + + /// + /// Represents an inequality condition. + /// + NotEqual = 1, + + /// + /// Represents a 'greater than' condition. + /// + GreaterThan = 2, + + /// + /// Represents a 'greater than or equal' condition. + /// + GreaterThanOrEqual = 3, + + /// + /// Represents a 'less than' condition. + /// + LessThan = 4, + + /// + /// Represents a 'less than or equal' condition. + /// + LessThanOrEqual = 5 +} diff --git a/src/Misc/BitzArt.CoreExtensions/Enums/OrderDirection.cs b/src/Misc/BitzArt.CoreExtensions/Enums/OrderDirection.cs new file mode 100644 index 0000000..5232836 --- /dev/null +++ b/src/Misc/BitzArt.CoreExtensions/Enums/OrderDirection.cs @@ -0,0 +1,39 @@ +namespace BitzArt; + +/// +/// Order direction (ascending/descending). +/// +public enum OrderDirection : byte +{ + /// + /// Ascending order direction. + /// + Ascending = 0, + + /// + /// Descending order direction. + /// + Descending = 1 +} + +/// +/// Extensions to . +/// +public static class OrderDirectionExtensions +{ + /// + /// Reverse the order direction. + /// + /// + /// + /// + public static OrderDirection Reverse(this OrderDirection orderDirection) + { + return orderDirection switch + { + OrderDirection.Ascending => OrderDirection.Descending, + OrderDirection.Descending => OrderDirection.Ascending, + _ => throw new ArgumentOutOfRangeException(nameof(orderDirection), orderDirection, null) + }; + } +} diff --git a/src/Misc/BitzArt.CoreExtensions/Extensions/TaskExtensions.cs b/src/Misc/BitzArt.CoreExtensions/Extensions/TaskExtensions.cs new file mode 100644 index 0000000..9c9d4bd --- /dev/null +++ b/src/Misc/BitzArt.CoreExtensions/Extensions/TaskExtensions.cs @@ -0,0 +1,51 @@ +namespace BitzArt; + +/// +/// Extension methods for . +/// +public static class TaskExtensions +{ + /// + /// Awaits the until it is completed or cancelled, while ignoring cancellation exceptions. + /// + /// The task to await. + /// Whether to ignore cancellation exceptions. + /// Determines whether to check for task cancellation by task status (if ) or by (if ). + public static Task IgnoreCancellation(this Task task, bool ignoreCancellation = true, bool byTaskStatus = true) + { + if (!ignoreCancellation) return task; + + return byTaskStatus + ? IgnoreCancellationByTaskCancelledAsync(task) + : IgnoreCancellationByExceptionAsync(task); + } + + private static async Task IgnoreCancellationByTaskCancelledAsync(Task task) + { + try + { + await task; + } + catch + { + if (task.IsCanceled) return; + throw; + } + } + + private static async Task IgnoreCancellationByExceptionAsync(Task task) + { + try + { + await task; + } + catch (OperationCanceledException) + { + return; + } + catch + { + throw; + } + } +} diff --git a/tests/Misc/BitzArt.CoreExtensions.Tests/BitzArt.CoreExtensions.Tests.csproj b/tests/Misc/BitzArt.CoreExtensions.Tests/BitzArt.CoreExtensions.Tests.csproj new file mode 100644 index 0000000..07e10bc --- /dev/null +++ b/tests/Misc/BitzArt.CoreExtensions.Tests/BitzArt.CoreExtensions.Tests.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + diff --git a/tests/Misc/BitzArt.CoreExtensions.Tests/TaskExtensionsTests.cs b/tests/Misc/BitzArt.CoreExtensions.Tests/TaskExtensionsTests.cs new file mode 100644 index 0000000..5ed4949 --- /dev/null +++ b/tests/Misc/BitzArt.CoreExtensions.Tests/TaskExtensionsTests.cs @@ -0,0 +1,44 @@ +namespace BitzArt.CoreExtensions.Tests; + +public class TaskExtensionsTests +{ + [Fact] + public async Task IgnoreCancellation_WhenTrue_ShouldHandleExceptionByIgnoring() + { + var cts = new CancellationTokenSource(); + cts.CancelAfter(10); + + await Task.Delay(100, cts.Token).IgnoreCancellation(true); + } + + [Fact] + public async Task IgnoreCancellation_WhenFalse_ShouldDoNothing() + { + var cts = new CancellationTokenSource(); + cts.CancelAfter(10); + + await Assert.ThrowsAnyAsync(() + => Task.Delay(100, cts.Token).IgnoreCancellation(false)); + } + + [Fact] + public async Task IgnoreCancellation_WhenTrueAndInnerOperationCancelled_ShouldHandleExceptionByIgnoring() + { + await TestMethodAsync().IgnoreCancellation(true); + } + + [Fact] + public async Task IgnoreCancellation_WhenFalseAndInnerOperationCancelled_ShouldDoNothing() + { + await Assert.ThrowsAnyAsync(() + => TestMethodAsync().IgnoreCancellation(false)); + } + + private async Task TestMethodAsync() + { + var cts = new CancellationTokenSource(); + cts.CancelAfter(10); + + await Task.Delay(100, cts.Token); + } +}