Directory.Packages.props
+8
-0
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 2829a75..d81292d 100644
@@ -11,6 +11,14 @@
</ItemGroup>
<ItemGroup>
<PackageVersion Include="LibGit2Sharp" Version="0.31.0" />
<PackageVersion
Include="Microsoft.Extensions.FileSystemGlobbing"
Version="11.0.0-preview.5.26302.115"
/>
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="11.0.0-preview.5.26302.115" />
<PackageVersion
Include="Microsoft.Extensions.Options.ConfigurationExtensions"
Version="11.0.0-preview.5.26302.115"
/>
</ItemGroup>
</Project>
src/Reviewer.Cli/Program.cs
+13
-0
diff --git a/src/Reviewer.Cli/Program.cs b/src/Reviewer.Cli/Program.cs
index 0f39e1e..1d60db6 100644
@@ -18,3 +18,16 @@ var reviewService = app.Services.GetRequiredService<ReviewService>();
var inputOptions = app.Services.GetRequiredService<IOptions<InputOptions>>();
reviewService.Review(new(inputOptions.Value.RepositoryPath, inputOptions.Value.CommitHash));
// using System;
// using System.IO;
// using Microsoft.Extensions.FileSystemGlobbing;
// var matcher = new Matcher();
// matcher.AddInclude("**");
// matcher.AddExclude("packages.lock.json");
// var results = matcher.GetResultsInFullPath(@"D:\reviewer");
// foreach (var result in results)
// {
// Console.WriteLine(result);
// }
src/Reviewer.Cli/Properties/launchSettings.json
+15
-0
diff --git a/src/Reviewer.Cli/Properties/launchSettings.json b/src/Reviewer.Cli/Properties/launchSettings.json
new file mode 100644
index 0000000..026af54
@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"first": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"commandLineArgs": "--RepositoryPath $(SolutionDir) --CommitHash 1a60def",
"workingDirectory": "$(ProjectDir)",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}
src/Reviewer.Cli/Reviewer.Cli.csproj
+7
-0
diff --git a/src/Reviewer.Cli/Reviewer.Cli.csproj b/src/Reviewer.Cli/Reviewer.Cli.csproj
index 530ab87..8c18fb8 100644
@@ -6,6 +6,13 @@
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
</PropertyGroup>
<ItemGroup>
<Content
Condition="'$(Configuration)' != 'Release'"
Include="appsettings.Development.json"
CopyToOutputDirectory="Always"
/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Reviewer\Reviewer.csproj" />
</ItemGroup>
<ItemGroup>
src/Reviewer.Cli/appsettings.Development.json
+5
-0
diff --git a/src/Reviewer.Cli/appsettings.Development.json b/src/Reviewer.Cli/appsettings.Development.json
new file mode 100644
index 0000000..b94f204
@@ -0,0 +1,5 @@
{
"DiffIgnore": [
"**/packages.lock.json"
]
}
src/Reviewer.Cli/packages.lock.json
+18
-14
diff --git a/src/Reviewer.Cli/packages.lock.json b/src/Reviewer.Cli/packages.lock.json
index 9c9aa77..d29988f 100644
@@ -115,11 +115,6 @@
"Microsoft.Extensions.FileSystemGlobbing": "11.0.0-preview.5.26302.115"
}
},
"Microsoft.Extensions.FileSystemGlobbing": {
"type": "Transitive",
"resolved": "11.0.0-preview.5.26302.115",
"contentHash": "r06T2D3sxcAb66nhN8m+0WCsRWq+1F9FRjQ6Jpupey9Z9y/MtSgFNCcjNhhaMgwJphmplPj8o90GHsczJ5JsCQ=="
},
"Microsoft.Extensions.Logging": {
"type": "Transitive",
"resolved": "11.0.0-preview.5.26302.115",
@@ -174,14 +169,6 @@
"Microsoft.Extensions.Logging": "11.0.0-preview.5.26302.115"
}
},
"Microsoft.Extensions.Options.ConfigurationExtensions": {
"type": "Transitive",
"resolved": "11.0.0-preview.5.26302.115",
"contentHash": "cbCXUxc5waGVaNXeSSj3KVtrf7hRV0qhYuzUu5aSH5dsdtkEfbHuNpcn+zNr5SRt8INsiQTtSWkf3ds/qKTAdw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "11.0.0-preview.5.26302.115"
}
},
"System.Diagnostics.EventLog": {
"type": "Transitive",
"resolved": "11.0.0-preview.5.26302.115",
@@ -190,7 +177,9 @@
"reviewer": {
"type": "Project",
"dependencies": {
"LibGit2Sharp": "[0.31.0, )"
"LibGit2Sharp": "[0.31.0, )",
"Microsoft.Extensions.FileSystemGlobbing": "[11.0.0-preview.5.26302.115, )",
"Microsoft.Extensions.Options.ConfigurationExtensions": "[11.0.0-preview.5.26302.115, )"
}
},
"LibGit2Sharp": {
@@ -201,6 +190,21 @@
"dependencies": {
"LibGit2Sharp.NativeBinaries": "[2.0.323]"
}
},
"Microsoft.Extensions.FileSystemGlobbing": {
"type": "CentralTransitive",
"requested": "[11.0.0-preview.5.26302.115, )",
"resolved": "11.0.0-preview.5.26302.115",
"contentHash": "r06T2D3sxcAb66nhN8m+0WCsRWq+1F9FRjQ6Jpupey9Z9y/MtSgFNCcjNhhaMgwJphmplPj8o90GHsczJ5JsCQ=="
},
"Microsoft.Extensions.Options.ConfigurationExtensions": {
"type": "CentralTransitive",
"requested": "[11.0.0-preview.5.26302.115, )",
"resolved": "11.0.0-preview.5.26302.115",
"contentHash": "cbCXUxc5waGVaNXeSSj3KVtrf7hRV0qhYuzUu5aSH5dsdtkEfbHuNpcn+zNr5SRt8INsiQTtSWkf3ds/qKTAdw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "11.0.0-preview.5.26302.115"
}
}
}
}
src/Reviewer/DiffIgnoreOptions.cs
+20
-0
diff --git a/src/Reviewer/DiffIgnoreOptions.cs b/src/Reviewer/DiffIgnoreOptions.cs
new file mode 100644
index 0000000..a1ad319
@@ -0,0 +1,20 @@
using Microsoft.Extensions.DependencyInjection;
namespace Reviewer;
public sealed class DiffIgnoreOptions
{
public string[] DiffIgnore { get; set; } = [];
}
internal static class DiffIgnoreOptionsCollectionExtensions
{
extension(IServiceCollection services)
{
public IServiceCollection AddDiffIgnoreOptions()
{
services.AddOptions<DiffIgnoreOptions>().BindConfiguration("").ValidateOnStart();
return services;
}
}
}
src/Reviewer/DiffProcessor.cs
+60
-0
diff --git a/src/Reviewer/DiffProcessor.cs b/src/Reviewer/DiffProcessor.cs
new file mode 100644
index 0000000..bdba161
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using LibGit2Sharp;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.Options;
namespace Reviewer;
public sealed class DiffProcessor(IOptions<DiffIgnoreOptions> options)
{
private readonly Matcher matcher = Matcher.CreateExclude(options.Value.DiffIgnore);
internal ReviewableDiff ProduceDiff(Commit commit)
{
var repository = ((IBelongToARepository)commit).Repository;
var parent = GetParentCommit(commit);
var patches = repository.Diff.Compare<Patch>(parent?.Tree, commit.Tree);
var filteredPatches = patches.Where(e => matcher.IsMatch(e.Path));
return new([.. filteredPatches]);
}
private static Commit? GetParentCommit(Commit commit) =>
commit.Parents.Take(2).ToArray() switch
{
[] => null,
[var parent] => parent,
[..] => throw new MultipleParentsException(),
};
}
file sealed class MultipleParentsException()
: NotImplementedException("Reviewing commits with multiple parents is not implemented.");
file static class MatcherExtensions
{
extension(Matcher matcher)
{
public static Matcher CreateExclude(IEnumerable<string> patterns)
{
var m = new Matcher();
m.AddInclude("**");
m.AddExcludePatterns(patterns);
return m;
}
public bool IsMatch(string path) => matcher.Match("/", path).HasMatches;
}
}
internal static class DiffProcessorServiceCollectionExtensions
{
extension(IServiceCollection services)
{
public IServiceCollection AddDiffProcessor() => services.AddDiffIgnoreOptions().AddTransient<DiffProcessor>();
}
}
src/Reviewer/ReviewService.cs
+8
-4
diff --git a/src/Reviewer/ReviewService.cs b/src/Reviewer/ReviewService.cs
index d30c39d..936fcc7 100644
@@ -4,7 +4,7 @@ using Microsoft.Extensions.Logging;
namespace Reviewer;
public sealed class ReviewService(ILogger<ReviewService> logger)
public sealed class ReviewService(ILogger<ReviewService> logger, DiffProcessor diffProcessor)
{
public void Review(Input input)
{
@@ -20,12 +20,16 @@ public sealed class ReviewService(ILogger<ReviewService> logger)
logger.LogNoCommitFound(input.CommitHash);
return;
}
var diff = diffProcessor.ProduceDiff(commit);
logger.LogInformation(
"Reviewing commit \"{Message}\" ({Hash}) by {Author}",
"Reviewing commit \"{Message}\" ({Hash}) by {Author} with {ChangeCount} patches",
commit.MessageShort,
commit.Id,
commit.Author.Name
commit.Author.Name,
diff.Patches.Length
);
logger.LogInformation("Patch:\n{Patch}", diff.ToString());
}
private static Repository? OpenRepository(string path)
@@ -45,6 +49,6 @@ public static class ReviewServiceServiceCollectionExtensions
{
extension(IServiceCollection services)
{
public IServiceCollection AddReviewService() => services.AddTransient<ReviewService>();
public IServiceCollection AddReviewService() => services.AddTransient<ReviewService>().AddDiffProcessor();
}
}
src/Reviewer/ReviewableDiff.cs
+9
-0
diff --git a/src/Reviewer/ReviewableDiff.cs b/src/Reviewer/ReviewableDiff.cs
new file mode 100644
index 0000000..1a6783a
@@ -0,0 +1,9 @@
using System.Linq;
using LibGit2Sharp;
namespace Reviewer;
internal sealed record ReviewableDiff(PatchEntryChanges[] Patches)
{
public override string ToString() => string.Concat(Patches.Select(p => p.Patch));
}
src/Reviewer/Reviewer.csproj
+2
-0
diff --git a/src/Reviewer/Reviewer.csproj b/src/Reviewer/Reviewer.csproj
index f726b8e..4a1bc4a 100644
@@ -5,5 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LibGit2Sharp" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
</ItemGroup>
</Project>
src/Reviewer/packages.lock.json
+28
-0
diff --git a/src/Reviewer/packages.lock.json b/src/Reviewer/packages.lock.json
index f2652f2..352ce63 100644
@@ -17,10 +17,38 @@
"LibGit2Sharp.NativeBinaries": "[2.0.323]"
}
},
"Microsoft.Extensions.FileSystemGlobbing": {
"type": "Direct",
"requested": "[11.0.0-preview.5.26302.115, )",
"resolved": "11.0.0-preview.5.26302.115",
"contentHash": "r06T2D3sxcAb66nhN8m+0WCsRWq+1F9FRjQ6Jpupey9Z9y/MtSgFNCcjNhhaMgwJphmplPj8o90GHsczJ5JsCQ=="
},
"Microsoft.Extensions.Options.ConfigurationExtensions": {
"type": "Direct",
"requested": "[11.0.0-preview.5.26302.115, )",
"resolved": "11.0.0-preview.5.26302.115",
"contentHash": "cbCXUxc5waGVaNXeSSj3KVtrf7hRV0qhYuzUu5aSH5dsdtkEfbHuNpcn+zNr5SRt8INsiQTtSWkf3ds/qKTAdw==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "11.0.0-preview.5.26302.115"
}
},
"LibGit2Sharp.NativeBinaries": {
"type": "Transitive",
"resolved": "2.0.323",
"contentHash": "Kg+fJGWhGj5qRXG0Ilj4ddhuodGXZg57yhfX6OVUDR0M2DKg/UR42/d74+qv5l1qotc1qJilo/ho7xQnULP6yA=="
},
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "11.0.0-preview.5.26302.115",
"contentHash": "rRRcEKScN/CuYr15WRzDqONxpQ52EXSSCMWYjG3dXaheKcZkwb172WtPvjH3rQ5mjJfNCFoy38CNAERvcKfgig=="
},
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "11.0.0-preview.5.26302.115",
"contentHash": "QHS547c+SiP/0RYZeAxvBak9JuF9LWJTp2T4Ansix1hIcxa+hoS1hOifHrxoid1uerM7Dy9v2jziFTLJEyszeg==",
"dependencies": {
"Microsoft.Extensions.Configuration": "11.0.0-preview.5.26302.115"
}
}
}
}