Skip to content

Commit

Permalink
Prepare v9.0.0 (Catnip) release (#83)
Browse files Browse the repository at this point in the history
* Fix minor bug in WaitAsync polyfill (potential cancellation or exception needs to be propagated in every case)

* Avoid making an unnecessary copy of the input string when deserializing JSON in .NET 4.5

* Minor code quality improvement

* Revert EvaluationDetails, FetchResult and RefreshResult from records to plain types as value equality won't work as expected (and not really useful either)

* Run tests on .NET 8

* Format code & cleanup usings

* Bump version

* Update samples

* Install .NET 8 in appveyor job

* Bump JAVA version for sonar scan

---------

Co-authored-by: Peter Csajtai <[email protected]>
  • Loading branch information
adams85 and z4kn4fein authored Nov 21, 2023
1 parent b6361d0 commit 70c1d69
Show file tree
Hide file tree
Showing 22 changed files with 56 additions and 48 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/linux-macOS-CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ jobs:
3.1.x
5.0.x
6.0.x
8.0.x
- name: Restore
run: dotnet restore src
- name: Test
run: |
dotnet test src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj -c Release -f netcoreapp3.1 --no-restore
dotnet test src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj -c Release -f net5.0 --no-restore
dotnet test src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj -c Release -f net6.0 --no-restore
dotnet test src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj -c Release -f net6.0 --no-restore
dotnet test src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj -c Release -f net8.0 --no-restore
7 changes: 4 additions & 3 deletions .github/workflows/sonar-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ jobs:
runs-on: windows-2022
steps:
- name: Set up JDK 11
uses: actions/setup-java@v1
uses: actions/setup-java@v3
with:
java-version: 1.11
java-version: 17
distribution: zulu
- uses: actions/checkout@v2
with:
fetch-depth: 0
Expand Down Expand Up @@ -51,4 +52,4 @@ jobs:
run: |
.\.sonar\scanner\dotnet-sonarscanner begin /k:"net-sdk" /d:sonar.host.url="https://sonarcloud.io" /o:"configcat" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.cs.opencover.reportsPaths="**/TestResults/**/coverage.opencover.xml" -d:sonar.cs.vstest.reportsPaths="**/TestResults/*.trx" /v:"${{ github.run_number }}" /d:sonar.exclusions="ConfigCatClient/Versioning/*" /d:sonar.coverage.exclusions="ConfigCatClient/Versioning/*"
dotnet test src\ConfigCat.Client.Tests\ConfigCat.Client.Tests.csproj -c Release --logger trx --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
14 changes: 9 additions & 5 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
environment:
build_version: 8.2.0
build_version: 9.0.0
version: $(build_version)-{build}
image: Visual Studio 2022
configuration: Release
Expand All @@ -16,11 +16,14 @@ dotnet_csproj:
file_version: $(build_version)
informational_version: $(build_version)
install:
- cmd: dotnet tool install -g InheritDocTool
build_script:
- ps: |
dotnet tool install -g InheritDocTool
Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile dotnet-install.ps1
./dotnet-install.ps1 -Channel 8.0
build_script:
- cmd: echo __BUILD__
- dotnet restore src/ConfigCatClient.sln
- dotnet build -c %configuration% /p:ContinuousIntegrationBuild=true src/ConfigCatClient.sln
- dotnet build -c %configuration% /p:ContinuousIntegrationBuild=true src/ConfigCatClient.sln
after_build:
- cmd: echo __PACK__
- inheritdoc -o
Expand All @@ -31,9 +34,10 @@ test_script:
- dotnet test src\ConfigCat.Client.Tests\ConfigCat.Client.Tests.csproj -f netcoreapp3.1 -c %configuration% --no-build
- dotnet test src\ConfigCat.Client.Tests\ConfigCat.Client.Tests.csproj -f net5.0 -c %configuration% --no-build
- dotnet test src\ConfigCat.Client.Tests\ConfigCat.Client.Tests.csproj -f net6.0 -c %configuration% --no-build
- dotnet test src\ConfigCat.Client.Tests\ConfigCat.Client.Tests.csproj -f net8.0 -c %configuration% --no-build
artifacts:
- path: artifacts\ConfigCat.Client.*.*nupkg
name: NuGet
name: NuGet
notifications:
- provider: Email
to:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics;
using ConfigCat.Client;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -23,7 +23,7 @@ public IActionResult Index()
{
Email = "[email protected]",
Country = "Canada",
Custom = new Dictionary<string, string>
Custom =
{
{"SubscriptionType", "Pro"},
{"Version", "1.0.0"}
Expand Down
2 changes: 1 addition & 1 deletion samples/ASP.NETCore/WebApplication/WebApplication.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\src\ConfigCatClient\ConfigCatClient.csproj" />
<!-- Use PackageReference instead of the ProjectReference above in your application. -->
<!--<PackageReference Include="ConfigCat.Client" Version="8.1.0" />-->
<!--<PackageReference Include="ConfigCat.Client" Version="9.0.0" />-->
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.*" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion samples/ConsoleApp/ConsoleApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\ConfigCatClient\ConfigCatClient.csproj" />
<!-- Use PackageReference instead of the ProjectReference above in your application. -->
<!--<PackageReference Include="ConfigCat.Client" Version="8.1.0" />-->
<!--<PackageReference Include="ConfigCat.Client" Version="9.0.0" />-->
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net45;net461;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
<TargetFrameworks>net45;net461;netcoreapp3.1;net5.0;net6.0;net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<AssemblyName>ConfigCatClientTests</AssemblyName>
<SignAssembly>true</SignAssembly>
Expand Down
4 changes: 2 additions & 2 deletions src/ConfigCat.Client.Tests/Helpers/LoggingHelper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Moq;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Moq;

namespace ConfigCat.Client;

Expand Down
2 changes: 0 additions & 2 deletions src/ConfigCat.Client.Tests/UserTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System;
using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ConfigCat.Client.Tests;
Expand Down
18 changes: 7 additions & 11 deletions src/ConfigCatClient/ConfigCatClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,26 +192,22 @@ private void Dispose(bool disposing)

if (disposing)
{
if (this.configService is IDisposable disposable)
{
disposable.Dispose();
}

this.overrideDataSource?.Dispose();
(this.configService as IDisposable)?.Dispose();
(this.overrideDataSource as IDisposable)?.Dispose();
}
else
{
// Execution gets here when consumer forgets to dispose the client instance.
// In this case we need to make sure that background work is stopped,
// otherwise it would go on endlessly, that is, we'd end up with a memory leak.
var autoPollConfigService = this.configService as AutoPollConfigService;
var localFileDataSource = this.overrideDataSource as LocalFileDataSource;
if (autoPollConfigService is not null || localFileDataSource is not null)
var configService = this.configService as IDisposable;
var localFileDataSource = this.overrideDataSource as IDisposable;
if (configService is not null || localFileDataSource is not null)
{
Task.Run(() =>
{
autoPollConfigService?.StopScheduler();
localFileDataSource?.StopWatch();
configService?.Dispose();
localFileDataSource?.Dispose();
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCatClient/Evaluation/EvaluateLogHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using ConfigCat.Client.Utils;
using System.Globalization;
using ConfigCat.Client.Utils;

namespace ConfigCat.Client.Evaluation;

Expand Down
4 changes: 2 additions & 2 deletions src/ConfigCatClient/Evaluation/EvaluationDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ConfigCat.Client;
/// <summary>
/// The evaluated value and additional information about the evaluation of a feature flag or setting.
/// </summary>
public abstract record class EvaluationDetails
public abstract class EvaluationDetails
{
internal static EvaluationDetails<TValue> FromEvaluateResult<TValue>(string key, TValue value, in EvaluateResult evaluateResult,
DateTime? fetchTime, User? user)
Expand Down Expand Up @@ -106,7 +106,7 @@ private protected EvaluationDetails(string key)
}

/// <inheritdoc/>
public sealed record class EvaluationDetails<TValue> : EvaluationDetails
public sealed class EvaluationDetails<TValue> : EvaluationDetails
{
/// <summary>
/// Initializes a new instance of the <see cref="EvaluationDetails{TValue}"/> class.
Expand Down
1 change: 0 additions & 1 deletion src/ConfigCatClient/Extensions/ObjectExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using ConfigCat.Client;

#if USE_NEWTONSOFT_JSON
Expand Down
12 changes: 7 additions & 5 deletions src/ConfigCatClient/Extensions/SerializationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,24 @@ internal static class SerializationExtensions
};
#endif

public static T? Deserialize<T>(this string json) => json.AsSpan().Deserialize<T>();
public static T? Deserialize<T>(this string json) => json.AsMemory().Deserialize<T>();

public static T? Deserialize<T>(this ReadOnlySpan<char> json)
// NOTE: It would be better to use ReadOnlySpan<char>, however when the full string is wrapped in a span, json.ToString() result in a copy of the string.
// This is not the case with ReadOnlyMemory<char>, so we use that until support for .NET 4.5 support is dropped.
public static T? Deserialize<T>(this ReadOnlyMemory<char> json)
{
#if USE_NEWTONSOFT_JSON
using var stringReader = new StringReader(json.ToString());
using var reader = new JsonTextReader(stringReader);
return Serializer.Deserialize<T>(reader);
#else
return JsonSerializer.Deserialize<T>(json);
return JsonSerializer.Deserialize<T>(json.Span);
#endif
}

public static T? DeserializeOrDefault<T>(this string json) => json.AsSpan().DeserializeOrDefault<T>();
public static T? DeserializeOrDefault<T>(this string json) => json.AsMemory().DeserializeOrDefault<T>();

public static T? DeserializeOrDefault<T>(this ReadOnlySpan<char> json)
public static T? DeserializeOrDefault<T>(this ReadOnlyMemory<char> json)
{
try
{
Expand Down
11 changes: 10 additions & 1 deletion src/ConfigCatClient/Extensions/TaskExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,16 @@ static async Task<T> Awaited(Task task, CancellationToken cancellationToken)
using (tokenRegistration)
{
var completedTask = await Task.WhenAny(task, cancellationTask).ConfigureAwait(false);
return completedTask is Task<T> taskWithResult ? taskWithResult.GetAwaiter().GetResult() : default!;
if (completedTask is Task<T> taskWithResult)
{
return taskWithResult.GetAwaiter().GetResult();
}
else
{
// Although the task has no return value, the potential cancellation or exception still needs to be propagated.
completedTask.GetAwaiter().GetResult();
return default!;
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCatClient/FetchResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace ConfigCat.Client;

internal readonly record struct FetchResult
internal readonly struct FetchResult
{
private static readonly object NotModifiedToken = new();

Expand Down
3 changes: 1 addition & 2 deletions src/ConfigCatClient/Override/IOverrideDataSource.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ConfigCat.Client.Override;

internal interface IOverrideDataSource : IDisposable
internal interface IOverrideDataSource
{
Dictionary<string, Setting> GetOverrides();

Expand Down
2 changes: 0 additions & 2 deletions src/ConfigCatClient/Override/LocalDictionaryDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ public LocalDictionaryDataSource(IDictionary<string, object> overrideValues, boo
}
}

public void Dispose() { /* no need to dispose anything */ }

public Dictionary<string, Setting> GetOverrides() => GetSettingsFromSource();

public Task<Dictionary<string, Setting>> GetOverridesAsync(CancellationToken cancellationToken = default) => Task.FromResult(GetSettingsFromSource());
Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCatClient/Override/LocalFileDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace ConfigCat.Client.Override;

internal sealed class LocalFileDataSource : IOverrideDataSource
internal sealed class LocalFileDataSource : IOverrideDataSource, IDisposable
{
private const int WAIT_TIME_FOR_UNLOCK = 200; // ms
private const int MAX_WAIT_ITERATIONS = 50; // ms
Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCatClient/ProjectConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static ProjectConfig Deserialize(string value)
var httpETagSpan = value.AsSpan(index, endIndex - index);

index = endIndex + 1;
var configJsonSpan = value.AsSpan(index);
var configJsonSpan = value.AsMemory(index);

Config? config;
string? configJson;
Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCatClient/RefreshResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ConfigCat.Client;
/// <summary>
/// Contains the result of an <see cref="IConfigCatClient.ForceRefresh"/> or <see cref="IConfigCatClient.ForceRefreshAsync"/> operation.
/// </summary>
public readonly record struct RefreshResult
public readonly struct RefreshResult
{
/// <summary>
/// Creates an instance of the <see cref="RefreshResult"/> struct which indicates that the operation was successful.
Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCatClient/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class User
/// <remarks>
/// The set of allowed attribute values depends on the comparison type of the condition which references the User Object attribute.<br/>
/// <see cref="string"/> values are supported by all comparison types (in some cases they need to be provided in a specific format though).<br/>
/// Some of the comparison types work with other types of values, as descibed below.
/// Some of the comparison types work with other types of values, as described below.
/// <para>
/// Text-based comparisons (EQUALS, IS ONE OF, etc.)<br/>
/// * accept <see cref="string"/> values,<br/>
Expand Down

0 comments on commit 70c1d69

Please sign in to comment.