Skip to content
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
2 changes: 2 additions & 0 deletions .github/scripts/check-doc-samples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ DOC=${DOC:-docs/plugin-author-guide.md}
SAMPLES_DIR=${SAMPLES_DIR:-samples/FrigateRelay.Samples.PluginGuide}

if [[ ! -f "$DOC" ]]; then
# NOTE: GitHub Actions ::error:: workflow commands must go to stdout to be rendered as
# annotations — do NOT redirect to stderr (Sonar S7677 is a false positive here).
echo "::error::Doc file not found: $DOC"
exit 1
fi
Expand Down
51 changes: 27 additions & 24 deletions docs/plugin-author-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ Log.RunningValidator(logger, validationPlugin.Name, "person");
var pass = await validationPlugin.ValidateAsync(ctx, default, CancellationToken.None).ConfigureAwait(false);
if (!pass.Passed)
{
Console.Error.WriteLine($"ERROR: validator expected Pass for label=person but got Fail({pass.Reason})");
await Console.Error.WriteLineAsync($"ERROR: validator expected Pass for label=person but got Fail({pass.Reason})");
return 1;
}

Expand All @@ -677,7 +677,7 @@ Log.RunningValidator(logger, validationPlugin.Name, "car");
var fail = await validationPlugin.ValidateAsync(carCtx, default, CancellationToken.None).ConfigureAwait(false);
if (fail.Passed)
{
Console.Error.WriteLine("ERROR: validator expected Fail for label=car but got Pass");
await Console.Error.WriteLineAsync("ERROR: validator expected Fail for label=car but got Pass");
return 1;
}

Expand All @@ -688,34 +688,37 @@ var request = new SnapshotRequest { Context = ctx };
var snapshot = await snapshotProvider.FetchAsync(request, CancellationToken.None).ConfigureAwait(false);
if (snapshot is null)
{
Console.Error.WriteLine("ERROR: snapshot provider returned null but was expected to return a stub result");
await Console.Error.WriteLineAsync("ERROR: snapshot provider returned null but was expected to return a stub result");
return 1;
}

Log.AllSucceeded(logger, snapshot.Bytes.Length);
return 0;

/// <summary>LoggerMessage delegates for the entry-point program.</summary>
internal static partial class Log
namespace FrigateRelay.Samples.PluginGuide
{
[LoggerMessage(
Level = LogLevel.Information,
Message = "Running {Contract} '{Name}'")]
internal static partial void RunningPlugin(ILogger logger, string contract, string name);

[LoggerMessage(
Level = LogLevel.Information,
Message = "Running IValidationPlugin '{Name}' with label={Label}")]
internal static partial void RunningValidator(ILogger logger, string name, string label);

[LoggerMessage(
Level = LogLevel.Information,
Message = "Running ISnapshotProvider '{Name}'")]
internal static partial void RunningProvider(ILogger logger, string name);

[LoggerMessage(
Level = LogLevel.Information,
Message = "All sample plugins exercised successfully. snapshot bytes={Bytes}")]
internal static partial void AllSucceeded(ILogger logger, int bytes);
/// <summary>LoggerMessage delegates for the entry-point program.</summary>
internal static partial class Log
{
[LoggerMessage(
Level = LogLevel.Information,
Message = "Running {Contract} '{Name}'")]
internal static partial void RunningPlugin(ILogger logger, string contract, string name);

[LoggerMessage(
Level = LogLevel.Information,
Message = "Running IValidationPlugin '{Name}' with label={Label}")]
internal static partial void RunningValidator(ILogger logger, string name, string label);

[LoggerMessage(
Level = LogLevel.Information,
Message = "Running ISnapshotProvider '{Name}'")]
internal static partial void RunningProvider(ILogger logger, string name);

[LoggerMessage(
Level = LogLevel.Information,
Message = "All sample plugins exercised successfully. snapshot bytes={Bytes}")]
internal static partial void AllSucceeded(ILogger logger, int bytes);
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.9" />
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.9" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.9" />
</ItemGroup>

<ItemGroup>
Expand Down
51 changes: 27 additions & 24 deletions samples/FrigateRelay.Samples.PluginGuide/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
var pass = await validationPlugin.ValidateAsync(ctx, default, CancellationToken.None).ConfigureAwait(false);
if (!pass.Passed)
{
Console.Error.WriteLine($"ERROR: validator expected Pass for label=person but got Fail({pass.Reason})");
await Console.Error.WriteLineAsync($"ERROR: validator expected Pass for label=person but got Fail({pass.Reason})");
return 1;
}

Expand All @@ -66,7 +66,7 @@
var fail = await validationPlugin.ValidateAsync(carCtx, default, CancellationToken.None).ConfigureAwait(false);
if (fail.Passed)
{
Console.Error.WriteLine("ERROR: validator expected Fail for label=car but got Pass");
await Console.Error.WriteLineAsync("ERROR: validator expected Fail for label=car but got Pass");
return 1;
}

Expand All @@ -77,33 +77,36 @@
var snapshot = await snapshotProvider.FetchAsync(request, CancellationToken.None).ConfigureAwait(false);
if (snapshot is null)
{
Console.Error.WriteLine("ERROR: snapshot provider returned null but was expected to return a stub result");
await Console.Error.WriteLineAsync("ERROR: snapshot provider returned null but was expected to return a stub result");
return 1;
}

Log.AllSucceeded(logger, snapshot.Bytes.Length);
return 0;

/// <summary>LoggerMessage delegates for the entry-point program.</summary>
internal static partial class Log
namespace FrigateRelay.Samples.PluginGuide
{
[LoggerMessage(
Level = LogLevel.Information,
Message = "Running {Contract} '{Name}'")]
internal static partial void RunningPlugin(ILogger logger, string contract, string name);

[LoggerMessage(
Level = LogLevel.Information,
Message = "Running IValidationPlugin '{Name}' with label={Label}")]
internal static partial void RunningValidator(ILogger logger, string name, string label);

[LoggerMessage(
Level = LogLevel.Information,
Message = "Running ISnapshotProvider '{Name}'")]
internal static partial void RunningProvider(ILogger logger, string name);

[LoggerMessage(
Level = LogLevel.Information,
Message = "All sample plugins exercised successfully. snapshot bytes={Bytes}")]
internal static partial void AllSucceeded(ILogger logger, int bytes);
/// <summary>LoggerMessage delegates for the entry-point program.</summary>
internal static partial class Log
{
[LoggerMessage(
Level = LogLevel.Information,
Message = "Running {Contract} '{Name}'")]
internal static partial void RunningPlugin(ILogger logger, string contract, string name);

[LoggerMessage(
Level = LogLevel.Information,
Message = "Running IValidationPlugin '{Name}' with label={Label}")]
internal static partial void RunningValidator(ILogger logger, string name, string label);

[LoggerMessage(
Level = LogLevel.Information,
Message = "Running ISnapshotProvider '{Name}'")]
internal static partial void RunningProvider(ILogger logger, string name);

[LoggerMessage(
Level = LogLevel.Information,
Message = "All sample plugins exercised successfully. snapshot bytes={Bytes}")]
internal static partial void AllSucceeded(ILogger logger, int bytes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.9" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@
{
// Note: string shorthand "BlueIris" → ActionEntry("BlueIris"); ParallelValidators defaults to false.
// No change needed here when ActionEntry gains new optional fields — default values handle back-compat.
// Object-form entries ({"Plugin":"X","ParallelValidators":true}) are NOT routed through this converter;
// IConfiguration.Bind maps them property-by-property via reflection (see ActionEntryJsonConverter for
// the JSON path — the two converters operate on disjoint code paths).
// Object-form entries — those with an explicit Plugin/ParallelValidators shape — are NOT
// routed through this converter; IConfiguration.Bind maps them property-by-property via
// reflection (see ActionEntryJsonConverter for the JSON path — the two converters operate
// on disjoint code paths).
if (value is string s)
{
// #14: reject empty/whitespace names at the converter boundary.
Expand All @@ -47,6 +48,6 @@
return new ActionEntry(s);
}

return base.ConvertFrom(context, culture, value)!;

Check warning on line 51 in src/FrigateRelay.Host/Configuration/ActionEntryTypeConverter.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this null-forgiving operator; nullable warnings are disabled here.

See more on https://sonarcloud.io/project/issues?id=blehnen_FrigateRelay&issues=AZ-QC5TNRHEeXNmghEXy&open=AZ-QC5TNRHEeXNmghEXy&pullRequest=90
}
}
Loading