Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ We support

Allocation allocation = null;

List<VariantDefinition> variants = null;
var variants = new List<VariantDefinition>();

bool telemetryEnabled = false;

Expand Down Expand Up @@ -349,8 +349,6 @@ We support

IEnumerable<IConfigurationSection> variantsSections = configurationSection.GetSection(ConfigurationFields.VariantsSectionName).GetChildren();

variants = new List<VariantDefinition>();

foreach (IConfigurationSection section in variantsSections)
{
if (int.TryParse(section.Key, out int _) && !string.IsNullOrEmpty(section[ConfigurationFields.NameKeyword]))
Expand Down Expand Up @@ -452,9 +450,19 @@ private FeatureDefinition ParseMicrosoftFeatureDefinition(IConfigurationSection

bool enabled = false;

IConfigurationSection conditions = configurationSection.GetSection(MicrosoftFeatureFlagFields.Conditions);
FeatureStatus featureStatus = FeatureStatus.Disabled;

Allocation allocation = null;

var variants = new List<VariantDefinition>();

bool telemetryEnabled = false;

Dictionary<string, string> telemetryMetadata = null;

IConfigurationSection conditionsSection = configurationSection.GetSection(MicrosoftFeatureFlagFields.Conditions);

string rawRequirementType = conditions[MicrosoftFeatureFlagFields.RequirementType];
string rawRequirementType = conditionsSection[MicrosoftFeatureFlagFields.RequirementType];

string rawEnabled = configurationSection[MicrosoftFeatureFlagFields.Enabled];

Expand All @@ -470,7 +478,9 @@ private FeatureDefinition ParseMicrosoftFeatureDefinition(IConfigurationSection

if (enabled)
{
IEnumerable<IConfigurationSection> filterSections = conditions.GetSection(MicrosoftFeatureFlagFields.ClientFilters).GetChildren();
featureStatus = FeatureStatus.Conditional;

IEnumerable<IConfigurationSection> filterSections = conditionsSection.GetSection(MicrosoftFeatureFlagFields.ClientFilters).GetChildren();

if (filterSections.Any())
{
Expand Down Expand Up @@ -498,11 +508,122 @@ private FeatureDefinition ParseMicrosoftFeatureDefinition(IConfigurationSection
}
}

IConfigurationSection allocationSection = configurationSection.GetSection(MicrosoftFeatureFlagFields.AllocationSectionName);

if (allocationSection.Exists())
{
allocation = new Allocation()
{
DefaultWhenDisabled = allocationSection[MicrosoftFeatureFlagFields.AllocationDefaultWhenDisabled],
DefaultWhenEnabled = allocationSection[MicrosoftFeatureFlagFields.AllocationDefaultWhenEnabled],
User = allocationSection.GetSection(MicrosoftFeatureFlagFields.UserAllocationSectionName).GetChildren().Select(userAllocation =>
{
return new UserAllocation()
{
Variant = userAllocation[MicrosoftFeatureFlagFields.AllocationVariantKeyword],
Users = userAllocation.GetSection(MicrosoftFeatureFlagFields.UserAllocationUsers).Get<IEnumerable<string>>()
};
}),
Group = allocationSection.GetSection(MicrosoftFeatureFlagFields.GroupAllocationSectionName).GetChildren().Select(groupAllocation =>
{
return new GroupAllocation()
{
Variant = groupAllocation[MicrosoftFeatureFlagFields.AllocationVariantKeyword],
Groups = groupAllocation.GetSection(MicrosoftFeatureFlagFields.GroupAllocationGroups).Get<IEnumerable<string>>()
};
}),
Percentile = allocationSection.GetSection(MicrosoftFeatureFlagFields.PercentileAllocationSectionName).GetChildren().Select(percentileAllocation =>
{
double from = 0;

double to = 0;

string rawFrom = percentileAllocation[MicrosoftFeatureFlagFields.PercentileAllocationFrom];

string rawTo = percentileAllocation[MicrosoftFeatureFlagFields.PercentileAllocationTo];

if (!string.IsNullOrEmpty(rawFrom))
{
from = ParseDouble(featureName, rawFrom, MicrosoftFeatureFlagFields.PercentileAllocationFrom);
}

if (!string.IsNullOrEmpty(rawTo))
{
to = ParseDouble(featureName, rawTo, MicrosoftFeatureFlagFields.PercentileAllocationTo);
}

return new PercentileAllocation()
{
Variant = percentileAllocation[MicrosoftFeatureFlagFields.AllocationVariantKeyword],
From = from,
To = to
};
}),
Seed = allocationSection[MicrosoftFeatureFlagFields.AllocationSeed]
};
}

IEnumerable<IConfigurationSection> variantsSections = configurationSection.GetSection(MicrosoftFeatureFlagFields.VariantsSectionName).GetChildren();

foreach (IConfigurationSection section in variantsSections)
{
if (int.TryParse(section.Key, out int _) && !string.IsNullOrEmpty(section[MicrosoftFeatureFlagFields.Name]))
{
StatusOverride statusOverride = StatusOverride.None;

string rawStatusOverride = section[MicrosoftFeatureFlagFields.VariantDefinitionStatusOverride];

if (!string.IsNullOrEmpty(rawStatusOverride))
{
statusOverride = ParseEnum<StatusOverride>(configurationSection.Key, rawStatusOverride, MicrosoftFeatureFlagFields.VariantDefinitionStatusOverride);
}

var variant = new VariantDefinition()
{
Name = section[MicrosoftFeatureFlagFields.Name],
ConfigurationValue = section.GetSection(MicrosoftFeatureFlagFields.VariantDefinitionConfigurationValue),
ConfigurationReference = section[MicrosoftFeatureFlagFields.VariantDefinitionConfigurationReference],
StatusOverride = statusOverride
};

variants.Add(variant);
}
}

IConfigurationSection telemetrySection = configurationSection.GetSection(MicrosoftFeatureFlagFields.Telemetry);

if (telemetrySection.Exists())
{
string rawTelemetryEnabled = telemetrySection[MicrosoftFeatureFlagFields.Enabled];

if (!string.IsNullOrEmpty(rawTelemetryEnabled))
{
telemetryEnabled = ParseBool(featureName, rawTelemetryEnabled, MicrosoftFeatureFlagFields.Enabled);
}

IConfigurationSection telemetryMetadataSection = telemetrySection.GetSection(MicrosoftFeatureFlagFields.Metadata);

if (telemetryMetadataSection.Exists())
{
telemetryMetadata = new Dictionary<string, string>();

telemetryMetadata = telemetryMetadataSection.GetChildren().ToDictionary(x => x.Key, x => x.Value);
}
}

return new FeatureDefinition()
{
Name = featureName,
EnabledFor = enabledFor,
RequirementType = requirementType
RequirementType = requirementType,
Status = featureStatus,
Allocation = allocation,
Variants = variants,
Telemetry = new TelemetryConfiguration
{
Enabled = telemetryEnabled,
Metadata = telemetryMetadata
}
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.FeatureManagement/ConfigurationFields.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ internal static class ConfigurationFields
public const string AllocationSectionName = "Allocation";
public const string AllocationDefaultWhenDisabled = "DefaultWhenDisabled";
public const string AllocationDefaultWhenEnabled = "DefaultWhenEnabled";
public const string UserAllocationSectionName = "User";
public const string AllocationVariantKeyword = "Variant";
public const string UserAllocationSectionName = "User";
public const string UserAllocationUsers = "Users";
public const string GroupAllocationSectionName = "Group";
public const string GroupAllocationGroups = "Groups";
Expand Down
27 changes: 26 additions & 1 deletion src/Microsoft.FeatureManagement/MicrosoftFeatureFlagFields.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Microsoft.FeatureManagement
{
//
// Microsoft feature flag schema: https://github.com/Azure/AppConfiguration/blob/main/docs/FeatureManagement/FeatureFlag.v1.1.0.schema.json
// Microsoft feature flag schema: https://github.com/Azure/AppConfiguration/blob/main/docs/FeatureManagement/FeatureFlag.v2.0.0.schema.json
internal static class MicrosoftFeatureFlagFields
{
public const string FeatureFlagsSectionName = "FeatureFlags";
Copy link
Member

@rossgrambo rossgrambo Feb 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets add support for "feature_flags" & "feature_management" as well here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should only support snake casing for Microsoft Feature Management schema.
@jimmyca15

Copy link
Member

@rossgrambo rossgrambo Feb 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of this file is snake case, but perhaps I'm misunderstanding how this file is used?

*I now see the updated PR

Expand All @@ -18,9 +18,34 @@ internal static class MicrosoftFeatureFlagFields
public const string ClientFilters = "client_filters";
public const string RequirementType = "requirement_type";

//
// Allocation keywords
public const string AllocationSectionName = "allocation";
public const string AllocationDefaultWhenDisabled = "default_when_disabled";
public const string AllocationDefaultWhenEnabled = "default_when_enabled";
public const string AllocationVariantKeyword = "variant";
public const string UserAllocationSectionName = "user";
public const string UserAllocationUsers = "users";
public const string GroupAllocationSectionName = "group";
public const string GroupAllocationGroups = "groups";
public const string PercentileAllocationSectionName = "percentile";
public const string PercentileAllocationFrom = "from";
public const string PercentileAllocationTo = "to";
public const string AllocationSeed = "seed";

//
// Client filter keywords
public const string Name = "name";
public const string Parameters = "parameters";

// Variants keywords
public const string VariantsSectionName = "variants";
public const string VariantDefinitionConfigurationValue = "configuration_value";
public const string VariantDefinitionConfigurationReference = "configuration_reference";
public const string VariantDefinitionStatusOverride = "status_override";

// Telemetry keywords
public const string Telemetry = "telemetry";
public const string Metadata = "metadata";
}
}
Loading