Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.0.1 release. #4

Merged
merged 8 commits into from
Jan 15, 2025
Merged
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
@@ -1,7 +1,12 @@
name: Deploy to NuGet.
name: Deploy to NuGet and Release section.

on:
create
push:
tags:
- "v*"

permissions:
contents: write # For release creation.

env:
BUILD_CONFIGURATION: Release
Expand All @@ -10,30 +15,26 @@ env:
NUGET_SOURCE_URL: 'https://api.nuget.org/v3/index.json'

jobs:
deploy_to_nuget:

deploy:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/heads/release/')

steps:
- name: Checkout.
uses: actions/checkout@v4

- name: Get package version.
run: |
Import-Module ./scripts/GetPackageVersion.psm1
Write-Host "Github ref: $Env:GITHUB_REF"
$version = .\scripts\GetPackageVersion.ps1 -RowContainingPackageVersion $Env:GITHUB_REF
$version = GetVersionFromGitHubRef -GitHubRef $Env:GITHUB_REF

Write-Host "Extracted version: '$version'"

if ($version -eq $null) {
Write-Error "Package version not found."
exit 1
}

if ($Env:GITHUB_REF -notlike "*$version") {
Write-Error "Invalid branch title format."
exit 1
}

echo "PACKAGE_VERSION=$version" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
shell: pwsh

Expand All @@ -52,4 +53,9 @@ jobs:
run: dotnet pack ${{ env.PROJECT_PATH }} --no-restore --no-build --configuration ${{ env.BUILD_CONFIGURATION }} --include-symbols -p:PackageVersion=${{ env.PACKAGE_VERSION }} --output ${{ env.PACKAGE_OUTPUT_DIRECTORY }}

- name: Push.
run: dotnet nuget push ${{ env.PACKAGE_OUTPUT_DIRECTORY }}/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s ${{ env.NUGET_SOURCE_URL }}
run: dotnet nuget push ${{ env.PACKAGE_OUTPUT_DIRECTORY }}/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s ${{ env.NUGET_SOURCE_URL }}

- name: Create release.
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
## 1.0.1
- Moved to tag pushing based deploying strategy.
- Fixed [IEnumerable logging issue](https://github.com/Vazovsk1y/Serilog.FluentDestructuring/issues/2).

## 1.0.0
- Initial release.
24 changes: 0 additions & 24 deletions scripts/GetPackageVersion.ps1

This file was deleted.

52 changes: 52 additions & 0 deletions scripts/GetPackageVersion.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
Function GetVersionFromGitHubRef {
Param (
# Last segment of ref path must be a valid semver string.
# Ex:
# refs/tags/client/v[semver_string]
# refs/heads/release/[semver_string]
# refs/heads/release/client/v[semver_string]
# refs/heads/release/v[semver_string]
# refs/tags/v[semver_string]
# refs/tags/[semver_string]
# ...

[string]$GitHubRef
)

$separator = '/'
$segments = $GitHubRef -split $separator
$versionSegment = $segments[-1]

Write-Host "Version segment: '$versionSegment'"

# SemVer Regex with optional 'v' character at the beginning.
$versionRegex = '^(v)?(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'

if ($versionSegment -match $versionRegex) {

if ($matches -eq $null) {
return $null
}

$MajorTag = $matches['major']
$MinorTag = $matches['minor']
$PatchTag = $matches['patch']

$PreReleaseTag = $matches['prerelease']
$BuildMetadataTag = $matches['buildmetadata']

$Version = "$MajorTag.$MinorTag.$PatchTag"

if ($PreReleaseTag) {
$Version += "-$PreReleaseTag"
}

if ($BuildMetadataTag) {
$Version += "+$BuildMetadataTag"
}

return $Version
} else {
return $null
}
}
135 changes: 65 additions & 70 deletions src/Serilog.FluentDestructuring/FluentDestructuringPolicy.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Reflection;
Expand All @@ -15,88 +16,86 @@ namespace Serilog.FluentDestructuring;
/// </summary>
public abstract class FluentDestructuringPolicy : IDestructuringPolicy
{
private readonly IReadOnlyDictionary<Type, EntityDestructuringConfiguration> _configurations;
private readonly IReadOnlyDictionary<Type, EntityDestructuringConfiguration> _typeToConfiguration;
private readonly FluentDestructuringPolicyOptions _options;

protected FluentDestructuringPolicy()
{
_options = new FluentDestructuringPolicyOptions();
var builder = new FluentDestructuringBuilder();
ConfigureCore(builder);
_configurations = builder.Build();
_typeToConfiguration = builder.Build();
}

public bool TryDestructure(object entity, ILogEventPropertyValueFactory propertyValueFactory, [NotNullWhen(true)] out LogEventPropertyValue? result)
{
ArgumentNullException.ThrowIfNull(entity);

var entityType = entity.GetType();
if (!_configurations.TryGetValue(entityType, out var entityConfiguration))

if (entity is IEnumerable)
{
result = CreateLogEventValueDefault(entity, entityType, propertyValueFactory);
return true;
result = null;
return false;
}

result = CreateLogEventPropertyValue(entity, entityConfiguration, propertyValueFactory);

var entityType = entity.GetType();
result = !_typeToConfiguration.TryGetValue(entityType, out var entityConfiguration) ?
CreateDefaultStructureValue(entity, entityType, propertyValueFactory)
:
CreateLogEventPropertyValue(entity, entityType, entityConfiguration, propertyValueFactory);

return true;
}

private StructureValue CreateLogEventValueDefault(
private StructureValue CreateDefaultStructureValue(
object entity,
Type entityType,
ILogEventPropertyValueFactory propertyValueFactory)
ILogEventPropertyValueFactory factory)
{
var logEventProperties = new List<LogEventProperty>();

foreach (var propertyInfo in GetPropertiesRecursive(entityType))
{
var propertyValue = GetPropertyValue(propertyInfo, entity);
if (propertyValue is null && _options.IgnoreNullProperties)
{
continue;
}

logEventProperties.Add(new LogEventProperty(propertyInfo.Name, propertyValueFactory.CreatePropertyValue(propertyValue, true)));
}
// NOTE: `StructureValue` ctor call on passed `IEnumerable<LogEventProperty>` parameter `ToArray` method, so I don't have to materialize twice calling `ToArray` or `ToList` here.
var logEventProperties = from propertyInfo in GetPropertiesRecursive(entityType)
let propertyValue = GetPropertyValue(propertyInfo, entity)
where propertyValue is not null || !_options.IgnoreNullProperties
select new LogEventProperty(propertyInfo.Name, factory.CreatePropertyValue(propertyValue, true));

return new StructureValue(logEventProperties, _options.ExcludeTypeTag ? null : entityType.Name);
}

private LogEventPropertyValue CreateLogEventPropertyValue(
object? entity,
EntityDestructuringConfiguration entityConfiguration,
ILogEventPropertyValueFactory propertyValueFactory)
Type entityType,
EntityDestructuringConfiguration configuration,
ILogEventPropertyValueFactory factory)
{
if (entityConfiguration.EntityDestructor is not null)
if (configuration.EntityDestructor is not null)
{
return entityConfiguration.EntityDestructor.CreateLogEventPropertyValue(entity, propertyValueFactory);
return configuration.EntityDestructor.CreateLogEventPropertyValue(entity, factory);
}

if (entity is null)
{
return ScalarValue.Null;
}

var entityType = entity.GetType();
var logEventProperties = new List<LogEventProperty>();

foreach (var propertyInfo in GetPropertiesRecursive(entityType))
{
var propertyValue = GetPropertyValue(propertyInfo, entity);

// NOTE: Global `IgnoreNullProperties` value will ignore custom conditional for destructuring rule applying.
if (propertyValue is null && _options.IgnoreNullProperties)
{
continue;
}

if (entityConfiguration.PropertyDestructuringConfigurations.TryGetValue(propertyInfo, out var propertyConfig))
if (configuration.PropertyDestructuringConfigurations.TryGetValue(propertyInfo, out var propertyConfig))
{
var logEventProperty = propertyConfig switch
{
SimplePropertyDestructuringConfiguration simplePropertyConfig => HandleSimpleProperty(entity, propertyValue, propertyInfo, simplePropertyConfig, propertyValueFactory),
SimplePropertyDestructuringConfiguration simplePropertyConfig => HandleSimpleProperty(entity, propertyValue, propertyInfo, simplePropertyConfig, factory),
InnerEntityDestructuringConfiguration innerEntityConfig => innerEntityConfig.ApplyDestructuringPredicate is not null && !innerEntityConfig.ApplyDestructuringPredicate.Invoke(entity) ?
new LogEventProperty(propertyInfo.Name, propertyValueFactory.CreatePropertyValue(propertyValue, true))
new LogEventProperty(propertyInfo.Name, factory.CreatePropertyValue(propertyValue, true))
:
new LogEventProperty(innerEntityConfig.PropertyAlias, CreateLogEventPropertyValue(propertyValue, innerEntityConfig.EntityConfiguration, propertyValueFactory)),
new LogEventProperty(innerEntityConfig.PropertyAlias, CreateLogEventPropertyValue(propertyValue, propertyInfo.PropertyType, innerEntityConfig.EntityConfiguration, factory)),
_ => throw new KeyNotFoundException(),
};

Expand All @@ -107,61 +106,34 @@ private LogEventPropertyValue CreateLogEventPropertyValue(
}
else
{
logEventProperties.Add(new LogEventProperty(propertyInfo.Name, propertyValueFactory.CreatePropertyValue(propertyValue, true)));
logEventProperties.Add(new LogEventProperty(propertyInfo.Name, factory.CreatePropertyValue(propertyValue, true)));
}
}

return new StructureValue(logEventProperties, _options.ExcludeTypeTag ? null : entityType.Name);
}

private static object? GetPropertyValue(PropertyInfo propertyInfo, object instance)
{
object? propertyValue;
try
{
propertyValue = Compile(propertyInfo).Invoke(instance);
}
catch (Exception ex)
{
SelfLog.WriteLine("The property accessor {0} threw exception {1}.", propertyInfo, ex);
propertyValue = $"The property accessor threw an exception: '{ex.GetType().Name}'.";
}

return propertyValue;

static Func<object, object?> Compile(PropertyInfo property)
{
var instanceParamExpr = Expression.Parameter(typeof(object), "instance");
ArgumentNullException.ThrowIfNull(property.DeclaringType);

var instanceExpr = Expression.Convert(instanceParamExpr, property.DeclaringType);
var propertyExpr = Expression.Property(instanceExpr, property);
var convertedPropExpr = Expression.Convert(propertyExpr, typeof(object));
return Expression.Lambda<Func<object, object?>>(convertedPropExpr, instanceParamExpr).Compile();
}
}

private static LogEventProperty? HandleSimpleProperty(
object instance,
object? propertyValue,
PropertyInfo propertyInfo,
SimplePropertyDestructuringConfiguration propertyConfig,
ILogEventPropertyValueFactory propertyValueFactory)
SimplePropertyDestructuringConfiguration propertyConfig,
ILogEventPropertyValueFactory factory)
{
if (propertyConfig.ApplyDestructuringPredicate is not null && !propertyConfig.ApplyDestructuringPredicate.Invoke(instance))
{
return new LogEventProperty(propertyInfo.Name, propertyValueFactory.CreatePropertyValue(propertyValue, true));
return new LogEventProperty(propertyInfo.Name, factory.CreatePropertyValue(propertyValue, true));
}

var result = propertyConfig.PropertyDestructor.CreateLogEventProperty(propertyConfig.PropertyAlias, propertyValue, propertyValueFactory);
var result = propertyConfig.PropertyDestructor.CreateLogEventProperty(propertyConfig.PropertyAlias, propertyValue, factory);
if (result is not null)
{
return result;
}

if (propertyConfig.PropertyDestructor is not IgnorePropertyDestructor)
{
result = new LogEventProperty(propertyConfig.PropertyAlias, propertyValueFactory.CreatePropertyValue(propertyValue, true));
result = new LogEventProperty(propertyConfig.PropertyAlias, factory.CreatePropertyValue(propertyValue, true));
}

return result;
Expand Down Expand Up @@ -190,13 +162,36 @@ private static IEnumerable<PropertyInfo> GetPropertiesRecursive(Type type)
type = type.BaseType;
}
}

internal void ConfigureOptions(Action<FluentDestructuringPolicyOptions> configureOptions)
private static object? GetPropertyValue(PropertyInfo propertyInfo, object instance)
{
ArgumentNullException.ThrowIfNull(configureOptions);
configureOptions.Invoke(_options);
object? propertyValue;
try
{
propertyValue = Compile(propertyInfo).Invoke(instance);
}
catch (Exception ex)
{
SelfLog.WriteLine("The property accessor {0} threw exception {1}.", propertyInfo, ex);
propertyValue = $"The property accessor threw an exception: '{ex.GetType().Name}'.";
}

return propertyValue;

static Func<object, object?> Compile(PropertyInfo property)
{
var instanceParamExpr = Expression.Parameter(typeof(object), "instance");
ArgumentNullException.ThrowIfNull(property.DeclaringType);

var instanceExpr = Expression.Convert(instanceParamExpr, property.DeclaringType);
var propertyExpr = Expression.Property(instanceExpr, property);
var convertedPropExpr = Expression.Convert(propertyExpr, typeof(object));
return Expression.Lambda<Func<object, object?>>(convertedPropExpr, instanceParamExpr).Compile();
}
}

internal void ConfigureOptions(Action<FluentDestructuringPolicyOptions> configureOptions) => configureOptions.Invoke(_options);

private void ConfigureCore(FluentDestructuringBuilder builder) => Configure(builder);

/// <summary>
Expand Down
Loading
Loading