Skip to content

Commit

Permalink
feat(git): Improve change detection (#5)
Browse files Browse the repository at this point in the history
- Try find Git repository
- Guard against not found repository
- Get last commit when working directory has no changes
  • Loading branch information
skarllot authored Dec 22, 2024
1 parent a49f2c5 commit c10cf18
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 48 deletions.
1 change: 0 additions & 1 deletion src/FlowPair/Agent/Operations/Login/LoginUseCase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using AutomaticInterface;
using Ciandt.FlowTools.FlowPair.Common;
using Ciandt.FlowTools.FlowPair.Flow;
using Ciandt.FlowTools.FlowPair.Flow.Contracts;
using Ciandt.FlowTools.FlowPair.Flow.Infrastructure;
using Ciandt.FlowTools.FlowPair.Flow.Operations.GenerateToken;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
using Ciandt.FlowTools.FlowPair.Agent.Infrastructure;
using Ciandt.FlowTools.FlowPair.Agent.Operations.Login;
using Ciandt.FlowTools.FlowPair.Agent.Operations.ReviewChanges.v1;
using Ciandt.FlowTools.FlowPair.ChangeTracking;
using Ciandt.FlowTools.FlowPair.Common;
using Ciandt.FlowTools.FlowPair.Flow.Operations.ProxyCompleteChat;
using Ciandt.FlowTools.FlowPair.Flow.Operations.ProxyCompleteChat.v1;
using Ciandt.FlowTools.FlowPair.Git.GetChanges;
using Ciandt.FlowTools.FlowPair.Support.Persistence;
using Ciandt.FlowTools.FlowPair.Support.Presentation;
using ConsoleAppFramework;
Expand All @@ -19,17 +19,19 @@ public class ReviewChangesCommand(
IAnsiConsole console,
IFileSystem fileSystem,
AgentJsonContext jsonContext,
IGitDiffExtractor gitDiffExtractor,
IGitGetChangesHandler getChangesHandler,
ILoginUseCase loginUseCase,
IProxyCompleteChatHandler completeChatHandler)
{
/// <summary>
/// Review changed files using Flow.
/// </summary>
/// <param name="path">Path to the repository.</param>
[Command("review")]
public int Execute()
public int Execute(
[Argument] string? path = null)
{
return (from diff in gitDiffExtractor.Extract().OkOr(0)
return (from diff in getChangesHandler.Extract(path).OkOr(0)
from session in loginUseCase.Execute(isBackground: true)
.UnwrapErrOr(0)
.Ensure(n => n == 0, 1)
Expand Down
40 changes: 0 additions & 40 deletions src/FlowPair/ChangeTracking/GitDiffExtractor.cs

This file was deleted.

3 changes: 3 additions & 0 deletions src/FlowPair/Common/FunctionalExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,7 @@ public static TErr UnwrapErrOr<TOk, TErr>(this Result<TOk, TErr> result, TErr fa
public static TOk? UnwrapOrNull<TOk, TErr>(this Result<TOk, TErr> result)
where TOk : class
where TErr : notnull => result.TryGet(out var ok, out _) ? ok : null;

public static T? UnwrapOrNull<T>(this Option<T> option)
where T : class => option.TryGet(out var value) ? value : null;
}
4 changes: 2 additions & 2 deletions src/FlowPair/DependencyInjection/AppContainer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Ciandt.FlowTools.FlowPair.Agent.Infrastructure;
using Ciandt.FlowTools.FlowPair.ChangeTracking;
using Ciandt.FlowTools.FlowPair.Flow.Infrastructure;
using Ciandt.FlowTools.FlowPair.Git.Infrastructure;
using Ciandt.FlowTools.FlowPair.Settings.Infrastructure;
using Ciandt.FlowTools.FlowPair.UserSessions.Infrastructure;
using Jab;
Expand All @@ -10,8 +10,8 @@ namespace Ciandt.FlowTools.FlowPair.DependencyInjection;
[ServiceProvider]
[Import(typeof(ISettingsModule))]
[Import(typeof(IUserSessionModule))]
[Import(typeof(IGitModule))]
[Import(typeof(IFlowModule))]
[Import(typeof(IAgentModule))]
[Import(typeof(IExternalModule))]
[Singleton(typeof(IGitDiffExtractor), typeof(GitDiffExtractor))]
public sealed partial class AppContainer;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace Ciandt.FlowTools.FlowPair.ChangeTracking;
namespace Ciandt.FlowTools.FlowPair.Git.GetChanges;

public sealed record FileChange(string Path, string Diff);
86 changes: 86 additions & 0 deletions src/FlowPair/Git/GetChanges/GitGetChangesHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System.Collections.Immutable;
using System.IO.Abstractions;
using AutomaticInterface;
using Ciandt.FlowTools.FlowPair.Common;
using LibGit2Sharp;
using Spectre.Console;

namespace Ciandt.FlowTools.FlowPair.Git.GetChanges;

public partial interface IGitGetChangesHandler;

[GenerateAutomaticInterface]
public class GitGetChangesHandler(
IFileSystem fileSystem,
IAnsiConsole console)
: IGitGetChangesHandler
{
public Option<ImmutableList<FileChange>> Extract(string? path)
{
path = TryFindRepository(fileSystem, path).UnwrapOrNull();
if (path is null)
{
console.MarkupLine("[red]Error:[/] Could not locate Git repository.");
return None;
}

using var repo = new Repository(path);
var builder = ImmutableList.CreateBuilder<FileChange>();

FillChanges(repo, builder, DiffTargets.Index);

if (builder.Count == 0)
{
FillChanges(repo, builder, DiffTargets.WorkingDirectory);
}

if (builder.Count == 0)
{
FillChangesFromLastCommit(repo, builder);
}

console.MarkupLine($"Found {builder.Count} changed files");
return Some(builder.ToImmutable());
}

private static void FillChanges(Repository repo, ImmutableList<FileChange>.Builder builder, DiffTargets diffTargets)
{
foreach (var changes in repo.Diff
.Compare<Patch>(repo.Head.Tip?.Tree, diffTargets)
.Where(p => !p.IsBinaryComparison && p.Status != ChangeKind.Deleted && p.Mode != Mode.Directory))
{
builder.Add(new FileChange(changes.Path, changes.Patch));
}
}

private static void FillChangesFromLastCommit(Repository repo, ImmutableList<FileChange>.Builder builder)
{
var lastCommit = repo.Head.Tip;
var parentCommit = lastCommit.Parents.FirstOrDefault();

foreach (var changes in repo.Diff
.Compare<Patch>(parentCommit?.Tree, lastCommit.Tree)
.Where(p => !p.IsBinaryComparison && p.Status != ChangeKind.Deleted && p.Mode != Mode.Directory))
{
builder.Add(new FileChange(changes.Path, changes.Patch));
}
}

private static Option<string> TryFindRepository(IFileSystem fileSystem, string? path)
{
var currentDirectory = fileSystem.DirectoryInfo.New(path ?? fileSystem.Directory.GetCurrentDirectory());
while (currentDirectory != null)
{
if (currentDirectory
.EnumerateDirectories(".git", SearchOption.TopDirectoryOnly)
.Any())
{
return currentDirectory.FullName;
}

currentDirectory = currentDirectory.Parent;
}

return None;
}
}
8 changes: 8 additions & 0 deletions src/FlowPair/Git/Infrastructure/IGitModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Ciandt.FlowTools.FlowPair.Git.GetChanges;
using Jab;

namespace Ciandt.FlowTools.FlowPair.Git.Infrastructure;

[ServiceProviderModule]
[Singleton(typeof(IGitGetChangesHandler), typeof(GitGetChangesHandler))]
public interface IGitModule;

0 comments on commit c10cf18

Please sign in to comment.