From acdb186c0517f6cb5f4599551b3cdc2ca3b09a80 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Tue, 26 May 2026 23:50:37 +0200 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=92=A5=20remove=20AssemblyContext=20f?= =?UTF-8?q?rom=20Savvyio.Core?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate reflection utilities into upstream Cuemon.Reflection package. The AssemblyContext class and its comprehensive test suite are removed from Savvyio.Core; callers must migrate to Cuemon.Reflection.AssemblyContext and update CurrentDomainAssemblies (property) to GetCurrentDomainAssemblies() (method). --- .../Reflection/AssemblyContext.cs | 1 - .../Reflection/AssemblyContextTest.cs | 185 ------------------ 2 files changed, 186 deletions(-) delete mode 100644 src/Savvyio.Core/Reflection/AssemblyContext.cs delete mode 100644 test/Savvyio.Core.Tests/Reflection/AssemblyContextTest.cs diff --git a/src/Savvyio.Core/Reflection/AssemblyContext.cs b/src/Savvyio.Core/Reflection/AssemblyContext.cs deleted file mode 100644 index ee95d3b1..00000000 --- a/src/Savvyio.Core/Reflection/AssemblyContext.cs +++ /dev/null @@ -1 +0,0 @@ -using Cuemon.Extensions.Collections.Generic; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Cuemon; namespace Savvyio.Reflection { /// /// Provides a set of static methods and properties to manage and filter assemblies in the current application domain. /// public static class AssemblyContext { private static readonly Lazy> AssemblyLoadFactory = new(() => AppDomain .CurrentDomain .GetAssemblies() .Where(AssemblyFilterCallback) .SelectMany(AssemblyDependenciesCallback) .Distinct() .Except(typeof(AssemblyContext).Assembly.Yield()) .ToList() .AsReadOnly()); private static Func _assemblyFilterCallback = DefaultAssemblyFilter; private static Func> _assemblyDependenciesCallback = DefaultAssemblyDependencies; private static Func _assemblyDependenciesFilterCallback = DefaultAssemblyDependenciesFilter; /// /// Gets or sets the function delegate that filters assemblies from the current application domain. /// /// The function delegate that filters assemblies from the current application domain. /// The default implementation filters away assemblies that suggest being part of the .NET runtime themselves. /// /// cannot be null. /// public static Func AssemblyFilterCallback { get => _assemblyFilterCallback; set => _assemblyFilterCallback = value ?? throw new ArgumentNullException(nameof(value)); } /// /// Gets or sets the function delegate that recursively discover dependencies for an assembly in the current application domain. /// /// The function delegate that recursively discover dependencies for an assembly in the current application domain. /// /// cannot be null. /// public static Func> AssemblyDependenciesCallback { get => _assemblyDependenciesCallback; set => _assemblyDependenciesCallback = value ?? throw new ArgumentNullException(nameof(value)); } /// /// Gets or sets the function delegate that filters assembly dependencies from the current application domain. /// /// The function delegate that filters assembly dependencies from the current application domain. /// The default implementation filters away assembly dependencies that suggest being part of the .NET runtime themselves. /// /// cannot be null. /// public static Func AssemblyDependenciesFilterCallback { get => _assemblyDependenciesFilterCallback; set => _assemblyDependenciesFilterCallback = value ?? throw new ArgumentNullException(nameof(value)); } /// /// Gets the qualified assemblies from the current application domain. /// /// The qualified assemblies from the current application domain. /// This result of this property is coupled with and . public static IReadOnlyList CurrentDomainAssemblies => AssemblyLoadFactory.Value; private static bool DefaultAssemblyFilter(Assembly assembly) { return assembly.FullName != null && !assembly.FullName.StartsWith(nameof(System)) && !assembly.FullName.StartsWith(nameof(Microsoft)); } private static bool DefaultAssemblyDependenciesFilter(AssemblyName assemblyName) { return !assemblyName.FullName.StartsWith(nameof(System)) && !assemblyName.FullName.StartsWith(nameof(Microsoft)); } private static IEnumerable DefaultAssemblyDependencies(Assembly assembly) { var stack = new Stack(); var guard = new HashSet(); yield return assembly; stack.Push(assembly); guard.Add(assembly.FullName); while (stack.TryPop(out var assemblyToTraverse)) { foreach (var assemblyName in assemblyToTraverse.GetReferencedAssemblies().Where(AssemblyDependenciesFilterCallback)) { if (!guard.Add(assemblyName.FullName)) { continue; } if (Patterns.TryInvoke(() => Assembly.Load(assemblyName), out var referencedAssembly) && referencedAssembly != null) { stack.Push(referencedAssembly); yield return referencedAssembly; } } } } } } \ No newline at end of file diff --git a/test/Savvyio.Core.Tests/Reflection/AssemblyContextTest.cs b/test/Savvyio.Core.Tests/Reflection/AssemblyContextTest.cs deleted file mode 100644 index 48f23786..00000000 --- a/test/Savvyio.Core.Tests/Reflection/AssemblyContextTest.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using Codebelt.Extensions.Xunit; -using Savvyio.Reflection; -using Xunit; - -namespace Savvyio.Reflection -{ - public class AssemblyContextTest : Test - { - public AssemblyContextTest(ITestOutputHelper output) : base(output) - { - } - - [Fact] - public void CurrentDomainAssemblies_ShouldReturnNonEmptyList() - { - var assemblies = AssemblyContext.CurrentDomainAssemblies; - - Assert.NotNull(assemblies); - Assert.NotEmpty(assemblies); - } - - [Fact] - public void CurrentDomainAssemblies_ShouldNotContainSavvyioCoreAssembly() - { - var savvyioCoreAssembly = typeof(AssemblyContext).Assembly; - - Assert.DoesNotContain(savvyioCoreAssembly, AssemblyContext.CurrentDomainAssemblies); - } - - [Fact] - public void CurrentDomainAssemblies_ShouldNotContainSystemOrMicrosoftAssemblies() - { - foreach (var assembly in AssemblyContext.CurrentDomainAssemblies) - { - Assert.False(assembly.FullName?.StartsWith(nameof(System), StringComparison.Ordinal), - $"Assembly '{assembly.FullName}' should have been filtered out."); - Assert.False(assembly.FullName?.StartsWith(nameof(Microsoft), StringComparison.Ordinal), - $"Assembly '{assembly.FullName}' should have been filtered out."); - } - } - - [Fact] - public void AssemblyFilterCallback_ShouldReturnDefaultNonNullDelegate() - { - var callback = AssemblyContext.AssemblyFilterCallback; - - Assert.NotNull(callback); - } - - [Fact] - public void AssemblyFilterCallback_ShouldAcceptCustomDelegate() - { - var original = AssemblyContext.AssemblyFilterCallback; - try - { - Func custom = _ => true; - AssemblyContext.AssemblyFilterCallback = custom; - - Assert.Same(custom, AssemblyContext.AssemblyFilterCallback); - } - finally - { - AssemblyContext.AssemblyFilterCallback = original; - } - } - - [Fact] - public void AssemblyFilterCallback_ShouldThrowArgumentNullException_WhenAssignedNull() - { - Assert.Throws(() => AssemblyContext.AssemblyFilterCallback = null); - } - - [Fact] - public void AssemblyDependenciesCallback_ShouldReturnDefaultNonNullDelegate() - { - var callback = AssemblyContext.AssemblyDependenciesCallback; - - Assert.NotNull(callback); - } - - [Fact] - public void AssemblyDependenciesCallback_ShouldAcceptCustomDelegate() - { - var original = AssemblyContext.AssemblyDependenciesCallback; - try - { - Func> custom = a => Enumerable.Repeat(a, 1); - AssemblyContext.AssemblyDependenciesCallback = custom; - - Assert.Same(custom, AssemblyContext.AssemblyDependenciesCallback); - } - finally - { - AssemblyContext.AssemblyDependenciesCallback = original; - } - } - - [Fact] - public void AssemblyDependenciesCallback_ShouldThrowArgumentNullException_WhenAssignedNull() - { - Assert.Throws(() => AssemblyContext.AssemblyDependenciesCallback = null); - } - - [Fact] - public void AssemblyDependenciesFilterCallback_ShouldReturnDefaultNonNullDelegate() - { - var callback = AssemblyContext.AssemblyDependenciesFilterCallback; - - Assert.NotNull(callback); - } - - [Fact] - public void AssemblyDependenciesFilterCallback_ShouldAcceptCustomDelegate() - { - var original = AssemblyContext.AssemblyDependenciesFilterCallback; - try - { - Func custom = _ => true; - AssemblyContext.AssemblyDependenciesFilterCallback = custom; - - Assert.Same(custom, AssemblyContext.AssemblyDependenciesFilterCallback); - } - finally - { - AssemblyContext.AssemblyDependenciesFilterCallback = original; - } - } - - [Fact] - public void AssemblyDependenciesFilterCallback_ShouldThrowArgumentNullException_WhenAssignedNull() - { - Assert.Throws(() => AssemblyContext.AssemblyDependenciesFilterCallback = null); - } - - [Fact] - public void AssemblyFilterCallback_DefaultFilter_ShouldIncludeNonSystemAssembly() - { - var callback = AssemblyContext.AssemblyFilterCallback; - var savvyioAssembly = typeof(AssemblyContext).Assembly; - - Assert.True(callback(savvyioAssembly)); - } - - [Fact] - public void AssemblyFilterCallback_DefaultFilter_ShouldExcludeSystemAssembly() - { - var callback = AssemblyContext.AssemblyFilterCallback; - var systemAssembly = typeof(string).Assembly; - - Assert.False(callback(systemAssembly)); - } - - [Fact] - public void AssemblyDependenciesFilterCallback_DefaultFilter_ShouldIncludeNonSystemAssemblyName() - { - var callback = AssemblyContext.AssemblyDependenciesFilterCallback; - var assemblyName = typeof(AssemblyContext).Assembly.GetName(); - - Assert.True(callback(assemblyName)); - } - - [Fact] - public void AssemblyDependenciesFilterCallback_DefaultFilter_ShouldExcludeSystemAssemblyName() - { - var callback = AssemblyContext.AssemblyDependenciesFilterCallback; - var assemblyName = typeof(string).Assembly.GetName(); - - Assert.False(callback(assemblyName)); - } - - [Fact] - public void AssemblyDependenciesCallback_DefaultCallback_ShouldYieldAtLeastTheInputAssembly() - { - var callback = AssemblyContext.AssemblyDependenciesCallback; - var assembly = typeof(AssemblyContext).Assembly; - - var result = callback(assembly).ToList(); - - Assert.Contains(assembly, result); - } - } -} From 48e8f7c55434a94763f77cdc047e6ee2c512138c Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Tue, 26 May 2026 23:50:51 +0200 Subject: [PATCH 2/6] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20update=20AssemblyConte?= =?UTF-8?q?xt=20calls=20to=20Cuemon.Reflection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace internal Savvyio.Reflection.AssemblyContext with external Cuemon.Reflection.AssemblyContext across all call sites. Updates SavvyioOptionsExtensions and both MessageConverter implementations (Newtonsoft.Json and Text.Json) to call GetCurrentDomainAssemblies() method instead of the removed CurrentDomainAssemblies property. --- .../SavvyioOptionsExtensions.cs | 8 ++++---- .../Converters/MessageConverter.cs | 4 ++-- .../Converters/MessageConverter.cs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Savvyio.Extensions.Dispatchers/SavvyioOptionsExtensions.cs b/src/Savvyio.Extensions.Dispatchers/SavvyioOptionsExtensions.cs index dd49abf1..f92e3428 100644 --- a/src/Savvyio.Extensions.Dispatchers/SavvyioOptionsExtensions.cs +++ b/src/Savvyio.Extensions.Dispatchers/SavvyioOptionsExtensions.cs @@ -1,11 +1,11 @@ -using Savvyio.Commands; +using Cuemon.Reflection; +using Savvyio.Commands; using Savvyio.Dispatchers; using Savvyio.Domain; using Savvyio.EventDriven; using Savvyio.Queries; using System.Linq; using System.Reflection; -using Savvyio.Reflection; using System.Runtime.CompilerServices; namespace Savvyio.Extensions @@ -43,7 +43,7 @@ public static SavvyioOptions UseAutomaticDispatcherDiscovery(this SavvyioOptions { if (bruteAssemblyScanning) { - options.AddDispatchers(AssemblyContext.CurrentDomainAssemblies.ToArray()); + options.AddDispatchers(AssemblyContext.GetCurrentDomainAssemblies().ToArray()); } else { @@ -63,7 +63,7 @@ public static SavvyioOptions UseAutomaticHandlerDiscovery(this SavvyioOptions op { if (bruteAssemblyScanning) { - options.AddHandlers(AssemblyContext.CurrentDomainAssemblies.ToArray()); + options.AddHandlers(AssemblyContext.GetCurrentDomainAssemblies().ToArray()); } else { diff --git a/src/Savvyio.Extensions.Newtonsoft.Json/Converters/MessageConverter.cs b/src/Savvyio.Extensions.Newtonsoft.Json/Converters/MessageConverter.cs index 5c58c1a3..380c3098 100644 --- a/src/Savvyio.Extensions.Newtonsoft.Json/Converters/MessageConverter.cs +++ b/src/Savvyio.Extensions.Newtonsoft.Json/Converters/MessageConverter.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reflection; using Cuemon.Extensions; +using Cuemon.Reflection; using Codebelt.Extensions.Newtonsoft.Json; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -11,7 +12,6 @@ using Savvyio.EventDriven.Messaging.CloudEvents.Cryptography; using Savvyio.Messaging; using Savvyio.Messaging.Cryptography; -using Savvyio.Reflection; namespace Savvyio.Extensions.Newtonsoft.Json.Converters { @@ -21,7 +21,7 @@ namespace Savvyio.Extensions.Newtonsoft.Json.Converters /// public class MessageConverter : JsonConverter { - internal static readonly Lazy> CloudEventTypes = new(() => AssemblyContext.CurrentDomainAssemblies.SelectMany(a => a.DefinedTypes.Where(ti => ti.HasInterfaces(typeof(ICloudEvent<>)) && + internal static readonly Lazy> CloudEventTypes = new(() => AssemblyContext.GetCurrentDomainAssemblies().SelectMany(a => a.DefinedTypes.Where(ti => ti.HasInterfaces(typeof(ICloudEvent<>)) && ti is { IsAbstract: false, IsInterface: false })).ToList()); /// diff --git a/src/Savvyio.Extensions.Text.Json/Converters/MessageConverter.cs b/src/Savvyio.Extensions.Text.Json/Converters/MessageConverter.cs index 37929a37..167706f4 100644 --- a/src/Savvyio.Extensions.Text.Json/Converters/MessageConverter.cs +++ b/src/Savvyio.Extensions.Text.Json/Converters/MessageConverter.cs @@ -6,13 +6,13 @@ using System.Text.Json.Serialization; using Cuemon.Extensions; using Cuemon.Extensions.Reflection; +using Cuemon.Reflection; using Cuemon.Extensions.Text.Json; using Savvyio.EventDriven; using Savvyio.EventDriven.Messaging.CloudEvents; using Savvyio.EventDriven.Messaging.CloudEvents.Cryptography; using Savvyio.Messaging; using Savvyio.Messaging.Cryptography; -using Savvyio.Reflection; namespace Savvyio.Extensions.Text.Json.Converters { @@ -22,7 +22,7 @@ namespace Savvyio.Extensions.Text.Json.Converters /// public class MessageConverter : JsonConverterFactory { - internal static readonly Lazy> CloudEventTypes = new(() => AssemblyContext.CurrentDomainAssemblies.SelectMany(a => a.DefinedTypes.Where(ti => ti.HasInterfaces(typeof(ICloudEvent<>)) && + internal static readonly Lazy> CloudEventTypes = new(() => AssemblyContext.GetCurrentDomainAssemblies().SelectMany(a => a.DefinedTypes.Where(ti => ti.HasInterfaces(typeof(ICloudEvent<>)) && ti is { IsAbstract: false, IsInterface: false })).ToList()); /// From 64888ca97e295b3dd1b76826a173608b3621c324 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Tue, 26 May 2026 23:51:03 +0200 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=91=B7=20improve=20CI=20pipeline=20st?= =?UTF-8?q?ructure=20with=20quality=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add optional run_mac_tests workflow dispatch input (default false) to control macOS test matrix execution and reduce CI costs. Introduce new test_qualitygate job that centralizes test result evaluation using require_success and require_success_or_skip helper functions. Refactor sonarcloud, codecov, codeql, and deploy jobs to depend on test_qualitygate instead of enumerating individual test jobs, simplifying workflow dependencies and improving maintainability. --- .github/workflows/ci-pipeline.yml | 73 ++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 13146357..1e41a5f1 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -12,6 +12,10 @@ on: options: - Debug - Release + run_mac_tests: + type: boolean + description: Run the macOS test matrix despite the additional cost and runtime. + default: false permissions: contents: read @@ -22,6 +26,7 @@ jobs: runs-on: ubuntu-24.04 outputs: run-privileged-jobs: ${{ steps.vars.outputs.run-privileged-jobs }} + run-mac-tests: ${{ steps.vars.outputs.run-mac-tests }} strong-name-key-filename: ${{ steps.vars.outputs.strong-name-key-filename }} build-switches: ${{ steps.vars.outputs.build-switches }} steps: @@ -29,6 +34,12 @@ jobs: name: calculate workflow variables shell: bash run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.run_mac_tests }}" == "true" ]]; then + echo "run-mac-tests=true" >> "$GITHUB_OUTPUT" + else + echo "run-mac-tests=false" >> "$GITHUB_OUTPUT" + fi + if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then echo "run-privileged-jobs=false" >> "$GITHUB_OUTPUT" echo "strong-name-key-filename=" >> "$GITHUB_OUTPUT" @@ -130,8 +141,9 @@ jobs: download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }} test_mac: + if: ${{ needs.init.outputs.run-mac-tests == 'true' }} name: call-test-mac - needs: [build, prepare_test] + needs: [init, build, prepare_test] strategy: fail-fast: false matrix: @@ -256,10 +268,61 @@ jobs: docker stop nats docker rm nats + test_qualitygate: + if: ${{ always() }} + name: test-qualitygate + needs: [init, test_linux, test_windows, test_mac, integration_test, integration_test_rabbitmq, integration_test_nats] + runs-on: ubuntu-24.04 + steps: + - name: Evaluate test results + shell: bash + env: + RUN_MAC_TESTS: ${{ needs.init.outputs.run-mac-tests }} + RUN_PRIVILEGED_JOBS: ${{ needs.init.outputs.run-privileged-jobs }} + TEST_LINUX_RESULT: ${{ needs.test_linux.result }} + TEST_WINDOWS_RESULT: ${{ needs.test_windows.result }} + TEST_MAC_RESULT: ${{ needs.test_mac.result }} + INTEGRATION_TEST_RESULT: ${{ needs.integration_test.result }} + INTEGRATION_TEST_RABBITMQ_RESULT: ${{ needs.integration_test_rabbitmq.result }} + INTEGRATION_TEST_NATS_RESULT: ${{ needs.integration_test_nats.result }} + run: | + require_success() { + local job_name="$1" + local job_result="$2" + + if [[ "$job_result" != "success" ]]; then + echo "::error::$job_name finished with '$job_result'." + exit 1 + fi + } + + require_success_or_skip() { + local job_name="$1" + local job_enabled="$2" + local job_result="$3" + + if [[ "$job_enabled" == "true" ]]; then + require_success "$job_name" "$job_result" + return + fi + + if [[ "$job_result" != "success" && "$job_result" != "skipped" ]]; then + echo "::error::$job_name finished with '$job_result' while disabled." + exit 1 + fi + } + + require_success "test_linux" "$TEST_LINUX_RESULT" + require_success "test_windows" "$TEST_WINDOWS_RESULT" + require_success_or_skip "test_mac" "$RUN_MAC_TESTS" "$TEST_MAC_RESULT" + require_success_or_skip "integration_test" "$RUN_PRIVILEGED_JOBS" "$INTEGRATION_TEST_RESULT" + require_success "integration_test_rabbitmq" "$INTEGRATION_TEST_RABBITMQ_RESULT" + require_success "integration_test_nats" "$INTEGRATION_TEST_NATS_RESULT" + sonarcloud: if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }} name: call-sonarcloud - needs: [init, build, test_linux, test_windows, test_mac, integration_test, integration_test_rabbitmq, integration_test_nats] + needs: [init, build, test_qualitygate] uses: codebeltnet/jobs-sonarcloud/.github/workflows/default.yml@v3 with: organization: geekle @@ -270,7 +333,7 @@ jobs: codecov: if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }} name: call-codecov - needs: [init, build, test_linux, test_windows, test_mac, integration_test, integration_test_rabbitmq, integration_test_nats] + needs: [init, build, test_qualitygate] uses: codebeltnet/jobs-codecov/.github/workflows/default.yml@v1 with: repository: codebeltnet/savvyio @@ -279,7 +342,7 @@ jobs: codeql: if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }} name: call-codeql - needs: [init, build, test_linux, test_windows, test_mac, integration_test, integration_test_rabbitmq, integration_test_nats] + needs: [init, build, test_qualitygate] uses: codebeltnet/jobs-codeql/.github/workflows/default.yml@v3 permissions: security-events: write @@ -287,7 +350,7 @@ jobs: deploy: if: github.event_name != 'pull_request' name: call-nuget - needs: [build, pack, test_linux, test_windows, test_mac, integration_test, integration_test_rabbitmq, integration_test_nats, sonarcloud, codecov, codeql] + needs: [build, pack, test_qualitygate, sonarcloud, codecov, codeql] uses: codebeltnet/jobs-nuget-push/.github/workflows/default.yml@v3 with: version: ${{ needs.build.outputs.version }} From 0836f1059d4e8c702efe55a82ae3858664e52146 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Tue, 26 May 2026 23:51:15 +0200 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=90=B3=20bump=20localstack=20docker?= =?UTF-8?q?=20image=20to=202026.05.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update LocalStack container image from 4.14.0 to 2026.05.0 in both Dockerfile.localstack and docker-compose.yml for access to latest AWS service emulation features and security updates. --- Dockerfile.localstack | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile.localstack b/Dockerfile.localstack index f6343dfd..ae292d29 100644 --- a/Dockerfile.localstack +++ b/Dockerfile.localstack @@ -1,5 +1,5 @@ # Use the LocalStack base image -FROM localstack/localstack:4.14.0 +FROM localstack/localstack:2026.05.0 # Expose the port for LocalStack EXPOSE 4566 diff --git a/docker-compose.yml b/docker-compose.yml index cbb26967..14f2544a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: localstack: - image: localstack/localstack:4.14.0 + image: localstack/localstack:2026.05.0 environment: - SERVICES=sns,sqs - DEBUG=0 From 43d9deb1629f3caadb4b6ef54bb53da330a57baa Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Tue, 26 May 2026 23:51:27 +0200 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=92=AC=20update=20changelog=20for=20p?= =?UTF-8?q?ending=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document breaking AssemblyContext removal, refactoring of call sites to use Cuemon.Reflection, CI pipeline improvements with optional macOS testing and centralized quality gate job, and LocalStack Docker image version bump. Add migration guidance for consumers affected by the breaking change. --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f4c942d..2442871d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder. +## [Unreleased] + +This is a patch release focused on consolidating the internal `AssemblyContext` reflection utility into the upstream `Cuemon.Reflection` package and tightening the CI pipeline structure. + +> [!TIP] +> The `Savvyio.Reflection.AssemblyContext` class has been removed from the `Savvyio.Core` assembly. Consumers referencing it directly must migrate to `Cuemon.Reflection.AssemblyContext` and replace the `CurrentDomainAssemblies` property with the `GetCurrentDomainAssemblies()` method. + +### Changed + +- `SavvyioOptionsExtensions` in `Savvyio.Extensions.Dispatchers` now calls `Cuemon.Reflection.AssemblyContext.GetCurrentDomainAssemblies()` to replace the removed `Savvyio.Reflection.AssemblyContext.CurrentDomainAssemblies` property, +- `MessageConverter` in `Savvyio.Extensions.Newtonsoft.Json` updated to use `Cuemon.Reflection.AssemblyContext.GetCurrentDomainAssemblies()`, +- `MessageConverter` in `Savvyio.Extensions.Text.Json` updated to use `Cuemon.Reflection.AssemblyContext.GetCurrentDomainAssemblies()`, +- LocalStack Docker image bumped from `4.14.0` to `2026.05.0` in `Dockerfile.localstack` and `docker-compose.yml`, +- CI pipeline now supports an opt-in `run_mac_tests` workflow dispatch boolean (default `false`) to run the macOS test matrix on demand rather than always, +- macOS test job (`test_mac`) is now guarded by the `run-mac-tests` output and requires `init` as an explicit dependency, +- New `test_qualitygate` job centralises evaluation of all test results (Linux, Windows, macOS, integration, RabbitMQ, NATS) using `require_success` and `require_success_or_skip` helper functions, +- `sonarcloud`, `codecov`, `codeql`, and `deploy` jobs now depend on `test_qualitygate` instead of enumerating each individual test job. + +### Removed + +- `AssemblyContext` class from the `Savvyio.Core` assembly (`Savvyio.Reflection` namespace); functionality is consolidated into `Cuemon.Reflection.AssemblyContext`, +- `AssemblyContextTest` unit tests removed alongside the deleted class. + ## [5.0.7] - 2026-05-26 This is a patch release focused on Azure.Identity compatibility across target frameworks, RabbitMQ queue durability correction, comprehensive test coverage expansion across multiple extensions, testability improvements with protected virtual methods and constructors for extensibility, dependency updates including LocalStack, NATS.Client, and Microsoft utility packages, and test reliability hardening for distributed mediator scenarios. From dd5f24084ce58899fa2692977ba4960183743a82 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Tue, 26 May 2026 23:53:39 +0200 Subject: [PATCH 6/6] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20update=20sonarcloud=20?= =?UTF-8?q?and=20codecov=20conditions=20for=20successful=20builds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 1e41a5f1..875f8f50 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -320,7 +320,7 @@ jobs: require_success "integration_test_nats" "$INTEGRATION_TEST_NATS_RESULT" sonarcloud: - if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }} + if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}} name: call-sonarcloud needs: [init, build, test_qualitygate] uses: codebeltnet/jobs-sonarcloud/.github/workflows/default.yml@v3 @@ -331,7 +331,7 @@ jobs: secrets: inherit codecov: - if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }} + if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}} name: call-codecov needs: [init, build, test_qualitygate] uses: codebeltnet/jobs-codecov/.github/workflows/default.yml@v1 @@ -340,7 +340,7 @@ jobs: secrets: inherit codeql: - if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }} + if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}} name: call-codeql needs: [init, build, test_qualitygate] uses: codebeltnet/jobs-codeql/.github/workflows/default.yml@v3