Skip to content

Commit

Permalink
Merge from development
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxShelestiuk committed Sep 29, 2023
2 parents 534114b + a87b233 commit 3c05e2e
Show file tree
Hide file tree
Showing 56 changed files with 3,768 additions and 266 deletions.
1 change: 1 addition & 0 deletions backend/Squirrel.Core/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ RUN dotnet publish "Squirrel.Core.WebAPI.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY Squirrel.Core/Squirrel.Core.WebAPI/Resources/SquirrelSetup.exe /app/Resources/
COPY Squirrel.Core/Squirrel.Core.WebAPI/Resources/SquirrelSetup-osx-x64.zip /app/Resources/
COPY --from=publish /app/publish .
ENV ASPNETCORE_URLS http://*:5050
ENTRYPOINT ["dotnet", "Squirrel.Core.WebAPI.dll"]
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ public interface IBranchService
Task<(BranchCommit?, bool)> FindHeadBranchCommitAsync(Branch branch);
Task<BranchDto> UpdateBranchAsync(int branchId, BranchUpdateDto branchUpdateDto);
Task DeleteBranchAsync(int branchId);
Task<BranchDto> MergeBranchAsync(int sourceId, int destId);
Task<ICollection<Commit>> GetCommitsFromBranchInternalAsync(int branchId, int destinationId);
Task<ICollection<BranchDetailsDto>> GetAllBranchDetailsAsync(int projectId, int selectedBranch);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ public BranchProfile()
{
CreateMap<Branch, BranchDto>()!.ReverseMap();
CreateMap<Branch, BranchCreateDto>()!.ReverseMap();
CreateMap<Branch, BranchDetailsDto>()
.ForMember(x => x.LastUpdatedBy, s => s.MapFrom(x => x.Author))
.ForMember(x => x.UpdatedAt, s => s.MapFrom(x => x.CreatedAt));
}
}
101 changes: 100 additions & 1 deletion backend/Squirrel.Core/Squirrel.Core.BLL/Services/BranchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,22 @@ namespace Squirrel.Core.BLL.Services;

public sealed class BranchService : BaseService, IBranchService
{
public BranchService(SquirrelCoreContext context, IMapper mapper) : base(context, mapper)
private readonly IUserIdGetter _userIdGetter;
private readonly IUserService _userService;
public BranchService(SquirrelCoreContext context, IMapper mapper, IUserIdGetter userIdGetter, IUserService userService) : base(context, mapper)
{
_userIdGetter = userIdGetter;
_userService = userService;
}

public async Task<BranchDto> AddBranchAsync(int projectId, BranchCreateDto branchDto)
{
var userId = _userIdGetter.GetCurrentUserId();
var user = await _userService.GetUserByIdInternalAsync(userId) ?? throw new EntityNotFoundException(nameof(User), userId);

var branch = _mapper.Map<Branch>(branchDto);
branch.ProjectId = projectId;
branch.CreatedBy = userId;
branch.IsActive = true;

await EnsureUniquenessAsync(branch.Name, projectId);
Expand All @@ -45,6 +53,7 @@ public async Task<BranchDto> AddBranchAsync(int projectId, BranchCreateDto branc
{
return headBranchCommit.IsHead ? (headBranchCommit, isHeadOnAnotherBranch) : throw new Exception("Last commit should be head!");
}

currentBranch = await _context.Branches
.Include(x => x.BranchCommits)
.ThenInclude(x => x.Commit)
Expand All @@ -68,6 +77,63 @@ public async Task<BranchDto> AddBranchAsync(int projectId, BranchCreateDto branc
return (await FindHeadBranchCommitAsync(branch)).Item1?.Id;
}

public async Task<BranchDto> MergeBranchAsync(int sourceId, int destId)
{
var dest = await GetFullBranchEntityAsync(destId) ?? throw new EntityNotFoundException(nameof(Branch), destId);

BranchCommit? lastCommit = default;
foreach (var commit in await GetCommitsFromBranchInternalAsync(sourceId, destId))
{
var branchCommit = new BranchCommit
{
CommitId = commit.Id,
BranchId = dest.Id,
IsMerged = true
};
dest.BranchCommits.Add(branchCommit);
lastCommit = branchCommit;
}

if(lastCommit is not null)
{
lastCommit.IsHead = true;
var previousHead = await FindHeadBranchCommitAsync(dest);
if (previousHead.Item2 && previousHead.Item1 is not null)
{
previousHead.Item1.IsHead = false;
_context.BranchCommits.Update(previousHead.Item1);
}
}

var entity = _context.Branches.Update(dest).Entity;
await _context.SaveChangesAsync();

return _mapper.Map<BranchDto>(entity);
}

public async Task<ICollection<Commit>> GetCommitsFromBranchInternalAsync(int branchId, int destinationId)
{
var source = await GetFullBranchEntityAsync(branchId) ?? throw new EntityNotFoundException(nameof(Branch), branchId);
var createdAt = source.CreatedAt;
var isOriginal = true;
var commits = new List<Commit>();

while (source is not null && source.Id != destinationId)
{
foreach (var commit in source.Commits
.Where(x => isOriginal ? true : x.CreatedAt <= createdAt)
.OrderByDescending(x => x.CreatedAt))
{
commits.Add(commit);
}

isOriginal = false;
source = await GetFullBranchEntityAsync(source.ParentBranchId ?? default);
}

return commits;
}


public BranchDto[] GetAllBranches(int projectId)
{
Expand All @@ -76,6 +142,28 @@ public BranchDto[] GetAllBranches(int projectId)
return _mapper.Map<BranchDto[]>(branches);
}

public async Task<ICollection<BranchDetailsDto>> GetAllBranchDetailsAsync(int projectId, int selectedBranch)
{
var entities = _context.Branches
.Include(x => x.Author)
.Where(x => x.ProjectId == projectId);
var branches = _mapper.Map<List<BranchDetailsDto>>(entities);

var selectedBranchCommits = await GetCommitsFromBranchInternalAsync(selectedBranch, 0);
foreach (var branch in branches)
{
var branchCommits = await GetCommitsFromBranchInternalAsync(branch.Id, 0);
var aheadCommits = branchCommits.Where(x => !selectedBranchCommits.Any(y => y.Id == x.Id));

var behindCommits = selectedBranchCommits.Where(x => !branchCommits.Any(y => y.Id == x.Id));

branch.Ahead = aheadCommits.Count();
branch.Behind = behindCommits.Count();
}

return branches;
}

public async Task DeleteBranchAsync(int branchId)
{
var entity = await _context.Branches.FirstOrDefaultAsync(x => x.Id == branchId);
Expand Down Expand Up @@ -105,6 +193,17 @@ public async Task<BranchDto> UpdateBranchAsync(int branchId, BranchUpdateDto bra
return _mapper.Map<BranchDto>(updatedEntity);
}

private async Task<Branch?> GetFullBranchEntityAsync(int branchId)
{
return await _context.Branches
.AsSplitQuery()
.Include(x => x.Commits)
.Include(x => x.ParentBranch)
.Include(x => x.BranchCommits)
.ThenInclude(x => x.Commit)
.FirstOrDefaultAsync(x => x.Id == branchId);
}

private async Task InheritBranchInternalAsync(Branch branch, int parentId)
{
if (await _context.Branches.AnyAsync(x => x.Id == parentId && branch.ProjectId == x.ProjectId))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Squirrel.Core.Common.DTO.Users;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Squirrel.Core.Common.DTO.Branch;
public class BranchDetailsDto: BranchDto
{
public UserDto? LastUpdatedBy { get; set; } = null!;
public int Ahead { get; set; }
public int Behind { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; } = null!;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Squirrel.Core.Common.DTO.Branch;

public sealed class BranchDto
public class BranchDto
{
public int Id { get; set; }
public string Name { get; set; } = null!;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Squirrel.Core.Common.DTO.Branch;

public class MergeBranchDto
{
public int SourceId { get; set; }
public int DestinationId { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ public void Configure(EntityTypeBuilder<Branch> builder)
builder.Property(x => x.IsActive).IsRequired();
builder.Property(x => x.ProjectId).IsRequired();

builder.Property(x => x.CreatedAt)
.IsRequired()
.HasDefaultValueSql(SquirrelCoreContext.SqlGetDateFunction)
.ValueGeneratedOnAdd();

builder.Property(x => x.CreatedBy)
.IsRequired(false);

builder.HasOne(x => x.ParentBranch)
.WithMany()
.HasForeignKey(x => x.ParentBranchId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public void Configure(EntityTypeBuilder<User> builder)
.IsRequired()
.OnDelete(DeleteBehavior.NoAction);

builder.HasMany(x => x.Branches)
.WithOne(x => x.Author)
.HasForeignKey(x => x.CreatedBy)
.IsRequired()
.OnDelete(DeleteBehavior.NoAction);

builder.HasMany(x => x.Commits)
.WithOne(x => x.Author)
.HasForeignKey(x => x.CreatedBy)
Expand Down
4 changes: 3 additions & 1 deletion backend/Squirrel.Core/Squirrel.Core.DAL/Entities/Branch.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using Squirrel.Core.DAL.Entities.Common;
using Squirrel.Core.DAL.Entities.Common.AuditEntity;
using Squirrel.Core.DAL.Entities.JoinEntities;

namespace Squirrel.Core.DAL.Entities;

public sealed class Branch : Entity<int>
public sealed class Branch : AuditEntity<int>
{
public string Name { get; set; } = string.Empty;
public bool IsActive { get; set; } = true;
Expand All @@ -12,6 +13,7 @@ public sealed class Branch : Entity<int>
public int? ParentBranchId { get; set; }
public Project Project { get; set; } = null!;
public Branch? ParentBranch { get; set; }
public User? Author { get; set; } = null!;
public ICollection<Commit> Commits { get; set; } = new List<Commit>();
public ICollection<BranchCommit> BranchCommits { get; set; } = new List<BranchCommit>();
public ICollection<PullRequest> PullRequestsFromThisBranch { get; set; } = new List<PullRequest>();
Expand Down
1 change: 1 addition & 0 deletions backend/Squirrel.Core/Squirrel.Core.DAL/Entities/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public sealed class User : Entity<int>
public bool IsGoogleAuth { get; set; }

public ICollection<Commit> Commits { get; set; } = new List<Commit>();
public ICollection<Branch> Branches { get; set; } = new List<Branch>();
public ICollection<Comment> Comments { get; set; } = new List<Comment>();
public ICollection<PullRequest> PullRequests { get; set; } = new List<PullRequest>();
public ICollection<UserProject> UserProjects { get; set; } = new List<UserProject>();
Expand Down
Loading

0 comments on commit 3c05e2e

Please sign in to comment.