-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR is the inital openfeature provider for the Harness feature flag SDK. It supports * basic targeting (via target name and identifier) * bool, number, string, evaluations Left to do: * structured evaluations * custom target attributes * unit testing * provider configuration Signed-off-by: Dave Johnston <[email protected]>
- Loading branch information
1 parent
1c3b6ed
commit 35158cd
Showing
4 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
src/OpenFeature.Contrib.Providers.Harness/HarnessAdapter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
using io.harness.cfsdk.client.dto; | ||
using OpenFeature.Model; | ||
|
||
namespace OpenFeature.Contrib.Providers.Harness; | ||
|
||
/// <summary> | ||
/// HarnessAdapter is the .NET adapter for the Harness feature flag SDK | ||
/// It provides functions to convert the OpenFeature EvaluationContext to | ||
/// a harness target, and functions to convert the Harness evaluation result | ||
/// to a OpenFeature ResolutionDetails. | ||
/// </summary> | ||
public static class HarnessAdapter | ||
{ | ||
/// <summary> | ||
/// Convert the Harness evaluation result to a OpenFeature ResolutionDetails. | ||
/// </summary> | ||
/// <param name="flagKey"></param> | ||
/// <param name="defaultValue"></param> | ||
/// <typeparam name="T"></typeparam> | ||
/// <returns></returns> | ||
public static ResolutionDetails<T> HarnessResponse<T>(string flagKey, T defaultValue) | ||
{ | ||
/* | ||
* string flagKey, T value, ErrorType errorType = ErrorType.None, string reason = null, | ||
string variant = null, string errorMessage = null | ||
*/ | ||
return new ResolutionDetails<T>( | ||
flagKey, | ||
defaultValue); | ||
} | ||
|
||
/// <summary> | ||
/// Convert the OpenFeature EvaluationContext to a harness target. | ||
/// </summary> | ||
/// <param name="context"></param> | ||
/// <returns></returns> | ||
public static Target CreateTarget(EvaluationContext context) | ||
{ | ||
// Get the identifier, if it is missing or empty return null | ||
if (context.TryGetValue("identifier", out var identifier) != true || identifier.IsString != true) | ||
{ | ||
return null; | ||
} | ||
|
||
// Get the name, if it is missing or empty return null | ||
if (context.TryGetValue("name", out var name) != true || name.IsString != true) | ||
{ | ||
return null; | ||
} | ||
|
||
// Create a target (different targets can get different results based on rules) | ||
// TODO we need to deal with target attributes | ||
// .Attributes(new Dictionary<string, string>(){{"email", "[email protected]"}}) | ||
Target target = Target.builder() | ||
.Name(name.AsString) | ||
.Identifier(identifier.AsString) | ||
.build(); | ||
return target; | ||
|
||
} | ||
|
||
|
||
} |
23 changes: 23 additions & 0 deletions
23
src/OpenFeature.Contrib.Providers.Harness/OpenFeature.Contrib.Providers.Harness.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<PackageId>OpenFeature.Contrib.Providers.Harness</PackageId> | ||
<VersionNumber>0.0.1</VersionNumber> | ||
<Version>$(VersionNumber)</Version> | ||
<AssemblyVersion>$(VersionNumber)</AssemblyVersion> | ||
<FileVersion>$(VersionNumber)</FileVersion> | ||
<Description>Harness Feature Flag provider for .NET</Description> | ||
<PackageProjectUrl>https://www.harness.io/products/feature-flags</PackageProjectUrl> | ||
<RepositoryUrl>https://github.com/open-feature/dotnet-sdk-contrib</RepositoryUrl> | ||
<Authors>Dave Johnston</Authors> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="System.Text.Json" Version="7.0.4" /> | ||
<PackageReference Include="ff-dotnet-server-sdk" Version="1.1.*" /> | ||
</ItemGroup> | ||
|
||
<PropertyGroup> | ||
<LangVersion>latest</LangVersion> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using io.harness.cfsdk.client.api; | ||
using OpenFeature.Model; | ||
|
||
namespace OpenFeature.Contrib.Providers.Harness; | ||
|
||
|
||
/// <summary> | ||
/// HarnessProvider is the .NET provider implementation for the Harness feature flag SDK | ||
/// </summary> | ||
public class Provider : FeatureProvider | ||
{ | ||
private const string HarnessProviderName = "Harness Provider"; | ||
|
||
private readonly Metadata _metadata = new (HarnessProviderName); | ||
private readonly ICfClient _client; | ||
|
||
/// <summary> | ||
/// Constructor of the Harness provider. | ||
/// </summary> | ||
public Provider(ICfClient client) | ||
{ | ||
_client = client; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override Metadata GetMetadata() | ||
{ | ||
return this._metadata; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override Task<ResolutionDetails<bool>> ResolveBooleanValue(string flagKey, bool defaultValue, EvaluationContext context = null) | ||
{ | ||
var result = _client.boolVariation(flagKey, HarnessAdapter.CreateTarget(context), defaultValue); | ||
return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, result)); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override Task<ResolutionDetails<string>> ResolveStringValue(string flagKey, string defaultValue, EvaluationContext context = null) | ||
{ | ||
var result = _client.stringVariation(flagKey, HarnessAdapter.CreateTarget(context), defaultValue); | ||
return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, result)); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override Task<ResolutionDetails<int>> ResolveIntegerValue(string flagKey, int defaultValue, EvaluationContext context = null) | ||
{ | ||
var result = _client.numberVariation(flagKey, HarnessAdapter.CreateTarget(context), defaultValue); | ||
return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, Convert.ToInt32(result))); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override Task<ResolutionDetails<double>> ResolveDoubleValue(string flagKey, double defaultValue, EvaluationContext context = null) | ||
{ | ||
var result = _client.numberVariation(flagKey, HarnessAdapter.CreateTarget(context), defaultValue); | ||
return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, result)); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override Task<ResolutionDetails<Value>> ResolveStructureValue(string flagKey, Value defaultValue, EvaluationContext context = null) | ||
{ | ||
// TODO need to implement this | ||
return Task.FromResult(HarnessAdapter.HarnessResponse(flagKey, defaultValue)); | ||
} | ||
|
||
|
||
} |