public FolderVersionEntry CreateDiff(IEnumerable <string> currentFilesList) { FolderVersionEntry[] currentHistory = ReadCurrentHistory(); var lastFilesVersion = new List <FileHistoryEntry>(); foreach (var historyEntry in currentHistory) { lastFilesVersion.AddRange(historyEntry.Files.Where(f => f.EditType == FileHistoryType.Added)); foreach (FileHistoryEntry deletedEntry in historyEntry.Files.Where(fv => fv.EditType == FileHistoryType.Deleted)) { FileHistoryEntry entryToRemove = lastFilesVersion.FirstOrDefault(fv => fv.Path == deletedEntry.Path); if (entryToRemove != null) { lastFilesVersion.Remove(entryToRemove); } else { //delete entry without added file, an error? } } } FolderVersionEntry currentVersion = new FolderVersionEntry(); List <FileHistoryEntry> touchedEntries = new List <FileHistoryEntry>(); foreach (string currentFilePath in currentFilesList) { string currentFileHash = hashService.ComputeFileHash(currentFilePath); FileHistoryEntry fileLastVersion = lastFilesVersion.FirstOrDefault(f => f.Path == currentFilePath); if (fileLastVersion != null) { if (fileLastVersion.Hash != currentFileHash) { currentVersion.AddEntry(currentFilePath, currentFileHash, FileHistoryType.Modified); } touchedEntries.Add(fileLastVersion); } else { currentVersion.AddEntry(currentFilePath, currentFileHash, FileHistoryType.Added); } } foreach (FileHistoryEntry deletedEntry in lastFilesVersion.Except(touchedEntries)) { currentVersion.AddEntry(deletedEntry.Path, string.Empty, FileHistoryType.Deleted); } SaveHistory(currentVersion); return(currentVersion); }
void ISessionAdapter.Save(FileHistoryEntry entry) { if (entry.RevisionId.HasValue) { Assert.That(entry.RevisionId.Value, Is.AnyOf(Revisions.Select(x => (object)x.Id).ToArray()), "File history entry must be linked to valid revision"); } var revision = Revisions.SingleOrDefault(x => x.Id == entry.RevisionId) ?? EmptyRevision; if (FileHistory.TryGetValue(revision, out var l)) { if (!l.Contains(entry)) { l.Add(entry); } } else { FileHistory[revision] = new List <FileHistoryEntry>() { entry }; } }
public async Task <Result> Execute(GetReviewStatus query) { var mergeRequest = await _repository.GetMergeRequestInfo(query.ReviewId.ProjectId, query.ReviewId.ReviewId); var latestRevision = await _session.Query <ReviewRevision>() .Where(x => x.ReviewId == query.ReviewId) .OrderByDescending(x => x.RevisionNumber) .FirstOrDefaultAsync(); IList <FileStatus> fileStatuses; { Review review = null; ReviewRevision revision = null; FileReview file = null; FileStatus dto = null; FileHistoryEntry historyEntry = null; fileStatuses = await _session.QueryOver(() => review) .JoinEntityAlias(() => revision, () => revision.Id == review.RevisionId) .JoinAlias(() => review.Files, () => file) .JoinEntityAlias(() => historyEntry, () => historyEntry.RevisionId == revision.Id && historyEntry.FileId == file.FileId) .Where(() => revision.ReviewId == query.ReviewId) .Select( Projections.Property(() => revision.RevisionNumber).WithAlias(() => dto.RevisionNumber), Projections.Property(() => review.UserId).WithAlias(() => dto.ReviewedBy), Projections.Property(() => historyEntry.FileName).WithAlias(() => dto.Path), Projections.Property(() => file.Status).WithAlias(() => dto.Status) ) .TransformUsing(Transformers.AliasToBean <FileStatus>()) .ListAsync <FileStatus>(); } List <DiscussionItem> discussions; { var q = from discussion in _session.Query <Discussion>() join revision in _session.Query <ReviewRevision>() on discussion.RevisionId equals revision.Id where revision.ReviewId == query.ReviewId join review in _session.Query <Review>() on discussion.RootComment.PostedInReviewId equals review.Id join author in _session.Query <ReviewUser>() on review.UserId equals author.Id select new DiscussionItem() { Author = author.UserName, State = discussion.State }; discussions = await q.ToListAsync(); } return(new Result { Title = mergeRequest.Title, Description = mergeRequest.Description, SourceBranch = mergeRequest.SourceBranch, TargetBranch = mergeRequest.TargetBranch, WebUrl = mergeRequest.WebUrl, MergeRequestState = mergeRequest.State, MergeStatus = mergeRequest.MergeStatus, RevisionForCurrentHead = mergeRequest.HeadCommit == latestRevision?.HeadCommit, LatestRevision = latestRevision?.RevisionNumber, CurrentHead = mergeRequest.HeadCommit, CurrentBase = mergeRequest.BaseCommit, FileStatuses = fileStatuses, FileSummary = fileStatuses .GroupBy(x => x.Path) .ToDictionary(x => x.Key, x => (object)new { ReviewedAt = x.Where(r => r.Status == FileReviewStatus.Reviewed).Select(r => r.RevisionNumber), ReviewedBy = x.Where(r => r.Status == FileReviewStatus.Reviewed).Select(r => r.ReviewedBy) }), UnresolvedDiscussions = discussions.Count(x => x.State == CommentState.NeedsResolution), ResolvedDiscussions = discussions.Count(x => x.State == CommentState.Resolved), Discussions = discussions, Author = mergeRequest.Author, }); }
private async Task <FileMatrix> BuildMatrix(GetFileMatrix query) { var revisions = await _session.Query <ReviewRevision>() .Where(x => x.ReviewId == query.ReviewId) .OrderBy(x => x.RevisionNumber) .ToListAsync(); var revisionIds = revisions.Select(x => (RevisionId) new RevisionId.Selected(x.RevisionNumber)); var mergeRequest = await _api.GetMergeRequestInfo(query.ReviewId.ProjectId, query.ReviewId.ReviewId); var hasProvisional = !revisions.Any() || mergeRequest.HeadCommit != revisions.Last().HeadCommit; if (hasProvisional) { revisionIds = revisionIds.Union(new RevisionId.Hash(mergeRequest.HeadCommit)); } var fileHistoryEntries = await _session.Query <FileHistoryEntry>() .Where(x => x.ReviewId == query.ReviewId) .GroupBy(x => x.FileId) .ToListAsync(); var provisionalDiff = new List <FileDiff>(); if (hasProvisional) { provisionalDiff = await _api.GetDiff(query.ReviewId.ProjectId, revisions.LastOrDefault()?.HeadCommit ?? mergeRequest.BaseCommit, mergeRequest.HeadCommit); if (_features.For("dont-show-excesive-files-from-rebases").IsActive) { if (revisions.Any() && revisions.Last().HeadCommit != mergeRequest.HeadCommit) { provisionalDiff = (await RelevantFilesFilter.Filter(provisionalDiff, fileHistoryEntries, query.ReviewId, mergeRequest.BaseCommit, mergeRequest.HeadCommit, _api)).ToList(); } } } var remainingDiffs = new HashSet <FileDiff>(provisionalDiff); var matrix = new FileMatrix(revisionIds); var revisionsMap = revisions.ToDictionary(x => (Guid?)x.Id); foreach (var(fileId, history) in fileHistoryEntries) { var sortedHistory = history .OrderBy(x => x.RevisionId.HasValue ? revisionsMap[x.RevisionId].RevisionNumber : int.MinValue); FileHistoryEntry previousEntry = null; foreach (var entry in sortedHistory) { if (entry.RevisionId == null) { previousEntry = entry; continue; } var rev = revisionsMap[entry.RevisionId]; string oldPath = previousEntry?.FileName ?? entry.FileName; var path = PathPair.Make(oldPath, entry.FileName); matrix.Append(new RevisionId.Selected(rev.RevisionNumber), path, entry); previousEntry = entry; } if (hasProvisional) { var diff = remainingDiffs.SingleOrDefault(x => x.Path.OldPath == previousEntry.FileName); remainingDiffs.Remove(diff); if (diff != null) { matrix.Append(new RevisionId.Hash(mergeRequest.HeadCommit), diff.Path, new FileHistoryEntry { FileId = fileId, FileName = diff.Path.NewPath, IsNew = diff.NewFile, IsDeleted = diff.DeletedFile, IsModified = true, IsRenamed = diff.RenamedFile }); } } } foreach (var diff in remainingDiffs) { matrix.Append(new RevisionId.Hash(mergeRequest.HeadCommit), diff.Path, new FileHistoryEntry { FileId = Guid.Empty, FileName = diff.Path.NewPath, IsNew = diff.NewFile, IsDeleted = diff.DeletedFile, IsModified = true, IsRenamed = diff.RenamedFile }); } matrix.TMP_FillFullRangeFilePath(); matrix.FillUnchanged(); matrix.Sort(DelegateComparer.For((FileMatrix.Entry e) => e.File.NewPath)); return(matrix); }