diff --git a/src/SearchBugs.Api/Endpoints/RepoEndpoints.cs b/src/SearchBugs.Api/Endpoints/RepoEndpoints.cs index c957320..cb8a01c 100644 --- a/src/SearchBugs.Api/Endpoints/RepoEndpoints.cs +++ b/src/SearchBugs.Api/Endpoints/RepoEndpoints.cs @@ -1,9 +1,12 @@ using MediatR; using Microsoft.AspNetCore.Mvc; +using SearchBugs.Application.Git.CommitChanges; using SearchBugs.Application.Git.CreateGitRepo; using SearchBugs.Application.Git.DeleteGitRepo; +using SearchBugs.Application.Git.GetCommitDiff; using SearchBugs.Application.Git.GetGitRepo; using SearchBugs.Application.Git.GetGitReposDetails; +using SearchBugs.Application.Git.GetListTree; using SearchBugs.Application.Git.GitHttpServer; namespace SearchBugs.Api.Endpoints; @@ -29,6 +32,32 @@ public static void MapRepoEndpoints(this WebApplication app) repo.MapGet("{url}/{path}", GetRepositoryDetails).WithName(nameof(GetRepositoryDetails)); repo.MapPost("", CreateRepository).WithName(nameof(CreateRepository)); repo.MapDelete("{url}", DeleteRepository).WithName(nameof(DeleteRepository)); + repo.MapGet("{url}/commit/{commitSha}", GetCommitDiff).WithName(nameof(GetCommitDiff)); + repo.MapPost("{url}/commit/{commitSha}", CommitChanges).WithName(nameof(CommitChanges)); + repo.MapGet("{url}/tree/{commitSha}", GetTree).WithName(nameof(GetTree)); + } + + public static async Task GetCommitDiff(string url, string commitSha, ISender sender) + { + var query = new GetCommitDiffQuery(url, commitSha); + var result = await sender.Send(query); + return Results.Ok(result); + } + + public record CommitChangeRequest(string Author, string Email, string Message, string Content); + + public static async Task CommitChanges([FromBody] CommitChangeRequest request, string url, string commitSha, ISender sender) + { + var command = new CommitChangeCommand(url, request.Author, request.Email, request.Message, request.Content); + var result = await sender.Send(command); + return Results.Ok(result); + } + + public static async Task GetTree(string url, string commitSha, ISender sender) + { + var query = new GetListTreeQuery(url, commitSha); + var result = await sender.Send(query); + return Results.Ok(result); } public static async Task GetRepositoryDetails(string url, string path, ISender sender) @@ -46,8 +75,6 @@ public static async Task GetRepositories(ISender sender) return Results.Ok(result); } - - public static async Task CreateRepository([FromBody] CreateGitRepositoryRequest request, ISender sender) { var command = new CreateGitRepoCommand(request.Name, request.Description, request.Url, request.ProjectId); diff --git a/src/SearchBugs.Api/Program.cs b/src/SearchBugs.Api/Program.cs index 99850be..261b4be 100644 --- a/src/SearchBugs.Api/Program.cs +++ b/src/SearchBugs.Api/Program.cs @@ -4,36 +4,41 @@ using SearchBugs.Infrastructure; using SearchBugs.Persistence; -var builder = WebApplication.CreateBuilder(args); - -builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); - -builder.Services.AddInfrastructure(); -builder.Services.AddPersistence(builder.Configuration); -builder.Services.AddApplication(); - -builder.Services.AddHttpContextAccessor(); - -var app = builder.Build(); - -if (app.Environment.IsDevelopment()) +public partial class Program { - app.UseSwagger(); - app.UseSwaggerUI(); - //app.ApplyMigrations(); + private static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + builder.Services.AddInfrastructure(); + builder.Services.AddPersistence(builder.Configuration); + builder.Services.AddApplication(); + + builder.Services.AddHttpContextAccessor(); + + var app = builder.Build(); + + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + //app.ApplyMigrations(); + } + app.MapAuthenticationsEndpoints(); + app.MapBugsEndpoints(); + app.MapUserEndpoints(); + app.MapProjectsEndpoints(); + app.MapRepoEndpoints(); + + app.UseHttpsRedirection(); + app.UseAuthentication(); + + app.UseMiddleware(); + app.Run(); + } } -app.MapAuthenticationsEndpoints(); -app.MapBugsEndpoints(); -app.MapUserEndpoints(); -app.MapProjectsEndpoints(); -app.MapRepoEndpoints(); - -app.UseHttpsRedirection(); -app.UseAuthentication(); - -//app.UseAuthorization(); -app.UseMiddleware(); -app.Run(); public partial class Program { } \ No newline at end of file diff --git a/src/SearchBugs.Api/SearchBugs.Api.csproj b/src/SearchBugs.Api/SearchBugs.Api.csproj index 6ee2861..1aa423a 100644 --- a/src/SearchBugs.Api/SearchBugs.Api.csproj +++ b/src/SearchBugs.Api/SearchBugs.Api.csproj @@ -7,6 +7,13 @@ 3cad7f34-1c5c-43a6-a304-e97d0203b339 + + + + + + + @@ -24,8 +31,4 @@ - - - - diff --git a/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommand.cs b/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommand.cs new file mode 100644 index 0000000..3a87f0b --- /dev/null +++ b/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommand.cs @@ -0,0 +1,5 @@ +using Shared.Messaging; + +namespace SearchBugs.Application.Git.CommitChanges; + +public record CommitChangeCommand(string Url, string AuthorName, string AuthorEmail, string CommitMessage, string FileContent) : ICommand; diff --git a/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommandHandler.cs b/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommandHandler.cs new file mode 100644 index 0000000..ccc2d16 --- /dev/null +++ b/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommandHandler.cs @@ -0,0 +1,18 @@ +using SearchBugs.Domain.Git; +using Shared.Messaging; +using Shared.Results; + +namespace SearchBugs.Application.Git.CommitChanges; + +internal sealed class CommitChangeCommandHandler : ICommandHandler +{ + private readonly IGitRepositoryService _gitRepositoryService; + public CommitChangeCommandHandler(IGitRepositoryService gitRepositoryService) + { + _gitRepositoryService = gitRepositoryService; + } + public Task Handle(CommitChangeCommand request, CancellationToken cancellationToken) + { + return Task.FromResult(_gitRepositoryService.CommitChanges(request.Url, request.AuthorName, request.AuthorEmail, request.CommitMessage)); + } +} diff --git a/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommandValidator.cs b/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommandValidator.cs new file mode 100644 index 0000000..3608af0 --- /dev/null +++ b/src/SearchBugs.Application/Git/CommitChanges/CommitChangeCommandValidator.cs @@ -0,0 +1,15 @@ +using FluentValidation; + +namespace SearchBugs.Application.Git.CommitChanges; + +internal sealed class CommitChangeCommandValidator : AbstractValidator +{ + public CommitChangeCommandValidator() + { + RuleFor(x => x.Url).NotEmpty(); + RuleFor(x => x.AuthorName).NotEmpty(); + RuleFor(x => x.AuthorEmail).NotEmpty(); + RuleFor(x => x.CommitMessage).NotEmpty(); + RuleFor(x => x.FileContent).NotEmpty(); + } +} diff --git a/src/SearchBugs.Application/Git/GetCommitDiff/CommitDiffResult.cs b/src/SearchBugs.Application/Git/GetCommitDiff/CommitDiffResult.cs new file mode 100644 index 0000000..a4ea4f3 --- /dev/null +++ b/src/SearchBugs.Application/Git/GetCommitDiff/CommitDiffResult.cs @@ -0,0 +1,5 @@ +using Shared.Messaging; + +namespace SearchBugs.Application.Git.GetCommitDiff; + +public record CommitDiffResult(string FilePath, string OldPath, string Status, string Patch) : IQuery>; diff --git a/src/SearchBugs.Application/Git/GetCommitDiff/GetCommitDiffQuery.cs b/src/SearchBugs.Application/Git/GetCommitDiff/GetCommitDiffQuery.cs new file mode 100644 index 0000000..6d9a5a3 --- /dev/null +++ b/src/SearchBugs.Application/Git/GetCommitDiff/GetCommitDiffQuery.cs @@ -0,0 +1,7 @@ + + +using Shared.Messaging; + +namespace SearchBugs.Application.Git.GetCommitDiff; + +public record GetCommitDiffQuery(string Url, string CommitSha) : IQuery>; \ No newline at end of file diff --git a/src/SearchBugs.Application/Git/GetCommitDiff/GetCommitDiffQueryHandler.cs b/src/SearchBugs.Application/Git/GetCommitDiff/GetCommitDiffQueryHandler.cs new file mode 100644 index 0000000..ab012f6 --- /dev/null +++ b/src/SearchBugs.Application/Git/GetCommitDiff/GetCommitDiffQueryHandler.cs @@ -0,0 +1,34 @@ +using SearchBugs.Domain.Git; +using Shared.Messaging; +using Shared.Results; + +namespace SearchBugs.Application.Git.GetCommitDiff; + +internal sealed class GetCommitDiffQueryHandler : IQueryHandler> +{ + private readonly IGitRepositoryService _gitRepositoryService; + + public GetCommitDiffQueryHandler(IGitRepositoryService gitRepositoryService) + { + _gitRepositoryService = gitRepositoryService; + } + + public Task>> Handle(GetCommitDiffQuery request, CancellationToken cancellationToken) + { + var commitDiffResult = _gitRepositoryService.GetCommitDiff(request.Url, request.CommitSha); + if (commitDiffResult.IsFailure) + { + return Task.FromResult(Result.Failure>(commitDiffResult.Error)); + } + + var commitDiffs = commitDiffResult.Value.Select(fileDiff => new CommitDiffResult + ( + FilePath: fileDiff.FilePath, + OldPath: fileDiff.OldPath, + Status: fileDiff.Status, + Patch: fileDiff.Patch + )); + + return Task.FromResult(Result.Success(commitDiffs)); + } +} diff --git a/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQuery.cs b/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQuery.cs new file mode 100644 index 0000000..fb72682 --- /dev/null +++ b/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQuery.cs @@ -0,0 +1,5 @@ +using Shared.Messaging; + +namespace SearchBugs.Application.Git.GetFileContents; + +public record GetFileContentQuery(string Url, string CommitSha, string FilePath) : IQuery; diff --git a/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQueryHandler.cs b/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQueryHandler.cs new file mode 100644 index 0000000..f707f0a --- /dev/null +++ b/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQueryHandler.cs @@ -0,0 +1,20 @@ +using SearchBugs.Domain.Git; +using Shared.Messaging; +using Shared.Results; + +namespace SearchBugs.Application.Git.GetFileContents; + +internal sealed class GetFileContentQueryHandler : IQueryHandler +{ + private readonly IGitRepositoryService _gitRepositoryService; + + public GetFileContentQueryHandler(IGitRepositoryService gitRepositoryService) + { + _gitRepositoryService = gitRepositoryService; + } + + public Task> Handle(GetFileContentQuery request, CancellationToken cancellationToken) + { + return Task.FromResult(_gitRepositoryService.GetFileContent(request.Url, request.CommitSha, request.FilePath)); + } +} diff --git a/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQueryValidator.cs b/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQueryValidator.cs new file mode 100644 index 0000000..8e8407d --- /dev/null +++ b/src/SearchBugs.Application/Git/GetFileContents/GetFileContentQueryValidator.cs @@ -0,0 +1,13 @@ +using FluentValidation; + +namespace SearchBugs.Application.Git.GetFileContents; + +internal sealed class GetFileContentQueryValidator : AbstractValidator +{ + public GetFileContentQueryValidator() + { + RuleFor(x => x.Url).NotEmpty(); + RuleFor(x => x.CommitSha).NotEmpty(); + RuleFor(x => x.FilePath).NotEmpty(); + } +} diff --git a/src/SearchBugs.Application/Git/GetListTree/GetListTreeQuery.cs b/src/SearchBugs.Application/Git/GetListTree/GetListTreeQuery.cs new file mode 100644 index 0000000..e2263a8 --- /dev/null +++ b/src/SearchBugs.Application/Git/GetListTree/GetListTreeQuery.cs @@ -0,0 +1,5 @@ +using Shared.Messaging; + +namespace SearchBugs.Application.Git.GetListTree; + +public record GetListTreeQuery(string Url, string CommitSha) : IQuery>; diff --git a/src/SearchBugs.Application/Git/GetListTree/GetListTreeQueryHandler.cs b/src/SearchBugs.Application/Git/GetListTree/GetListTreeQueryHandler.cs new file mode 100644 index 0000000..0851929 --- /dev/null +++ b/src/SearchBugs.Application/Git/GetListTree/GetListTreeQueryHandler.cs @@ -0,0 +1,22 @@ + +using SearchBugs.Domain.Git; +using Shared.Messaging; +using Shared.Results; + +namespace SearchBugs.Application.Git.GetListTree; + +internal sealed class GetListTreeQueryHandler : IQueryHandler> +{ + private readonly IGitRepositoryService _gitRepositoryService; + + public GetListTreeQueryHandler(IGitRepositoryService gitRepositoryService) + { + _gitRepositoryService = gitRepositoryService; + } + public Task>> Handle(GetListTreeQuery request, CancellationToken cancellationToken) + { + return Task.FromResult(_gitRepositoryService.ListTree(request.CommitSha, request.Url) + .Map(tree => + tree.Select(item => new GitTreeItemResult(item.Path, item.Name, item.Type, "")))); + } +} diff --git a/src/SearchBugs.Application/Git/GetListTree/GitListTreeQueryValidator.cs b/src/SearchBugs.Application/Git/GetListTree/GitListTreeQueryValidator.cs new file mode 100644 index 0000000..ca2722e --- /dev/null +++ b/src/SearchBugs.Application/Git/GetListTree/GitListTreeQueryValidator.cs @@ -0,0 +1,12 @@ +using FluentValidation; + +namespace SearchBugs.Application.Git.GetListTree; + +internal sealed class GitListTreeQueryValidator : AbstractValidator +{ + public GitListTreeQueryValidator() + { + RuleFor(x => x.Url).NotEmpty(); + RuleFor(x => x.CommitSha).NotEmpty(); + } +} diff --git a/src/SearchBugs.Application/Git/GetListTree/GitTreeItemResult.cs b/src/SearchBugs.Application/Git/GetListTree/GitTreeItemResult.cs new file mode 100644 index 0000000..e016334 --- /dev/null +++ b/src/SearchBugs.Application/Git/GetListTree/GitTreeItemResult.cs @@ -0,0 +1,3 @@ +namespace SearchBugs.Application.Git.GetListTree; + +public record GitTreeItemResult(string Path, string Name, string Type, string Url); \ No newline at end of file diff --git a/src/SearchBugs.Domain/Git/IGitRepositoryService.cs b/src/SearchBugs.Domain/Git/IGitRepositoryService.cs index 2ae74b4..b13b66d 100644 --- a/src/SearchBugs.Domain/Git/IGitRepositoryService.cs +++ b/src/SearchBugs.Domain/Git/IGitRepositoryService.cs @@ -1,5 +1,17 @@ -namespace SearchBugs.Domain.Git; +using SearchBugs.Infrastructure.Services; +using Shared.Results; + +namespace SearchBugs.Domain.Git; public interface IGitRepositoryService { + Result CheckoutBranch(string repoPath, string branchName); + Result CommitChanges(string repoPath, string authorName, string authorEmail, string commitMessage); + Result> CompareCommits(string repoPath, string baseCommitSha, string compareCommitSha); + Result> GetCommitDiff(string repoPath, string commitSha); + Result> GetContributors(string repoPath); + Result> GetFileBlame(string repoPath, string filePath); + Result GetFileContent(string repoPath, string commitSha, string filePath); + Result> ListTree(string commitSha, string repoPath); + Result MergeBranches(string repoPath, string sourceBranchName, string targetBranchName, string mergerName, string mergerEmail); } \ No newline at end of file diff --git a/src/SearchBugs.Ui/src/hooks/useApi.ts b/src/SearchBugs.Ui/src/hooks/useApi.ts index f0688f9..bfd5e05 100644 --- a/src/SearchBugs.Ui/src/hooks/useApi.ts +++ b/src/SearchBugs.Ui/src/hooks/useApi.ts @@ -5,8 +5,8 @@ interface ErrorResult { } interface ApiResult { - value: T[]; - error: ErrorResult[]; + value: T; + error: ErrorResult; isFailure : boolean; isSuccess : boolean; } diff --git a/src/SearchBugs.Ui/src/layouts/Main.tsx b/src/SearchBugs.Ui/src/layouts/Main.tsx index 557a8b2..497c1ee 100644 --- a/src/SearchBugs.Ui/src/layouts/Main.tsx +++ b/src/SearchBugs.Ui/src/layouts/Main.tsx @@ -31,7 +31,7 @@ const MainLayout = () => {
-
+
diff --git a/src/SearchBugs.Ui/src/pages/BugAddPage.tsx b/src/SearchBugs.Ui/src/pages/BugAddPage.tsx index 87388cd..5ba7ff5 100644 --- a/src/SearchBugs.Ui/src/pages/BugAddPage.tsx +++ b/src/SearchBugs.Ui/src/pages/BugAddPage.tsx @@ -1,62 +1,54 @@ - - import { Button } from "@/components/ui/button" - import { - Card, - CardContent, - } from "@/components/ui/card" - import { Input } from "@/components/ui/input" - import { Label } from "@/components/ui/label" -import { Textarea } from "@/components/ui/textarea" +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; export const BugAddPage = () => { - return ( -
-
-
-

- Report a Bug -

-
- - + return ( +
+
+
+

+ Report a Bug +

+
+ + +
+
+ + +
+
+ + +
+
+ +