public void Commit(string comment, User user, DateTime timeStamp, bool allowEmpty = true) { var userString = $"{user.UserName} <{user.Email}>"; var time = timeStamp.ToLocalTime().ToString(); gitCmd.Commit(localPath, comment, userString, time); }
static void ProcessHistoryInternal(DXVcsWrapper vcsWrapper, GitWrapper gitWrapper, RegisteredUsers users, User defaultUser, string localGitDir, TrackBranch branch, IList<CommitItem> commits, SyncHistoryWrapper syncHistory) { ProjectExtractor extractor = new ProjectExtractor(commits, (item) => { var localCommits = vcsWrapper.GetCommits(item.TimeStamp, item.Items).Where(x => !IsLabel(x)).ToList(); bool hasModifications = false; GitCommit last = null; string token = syncHistory.CreateNewToken(); foreach (var localCommit in localCommits) { string localProjectPath = Path.Combine(localGitDir, localCommit.Track.ProjectPath); DirectoryHelper.DeleteDirectory(localProjectPath); string trackPath = branch.GetTrackRoot(localCommit.Track); vcsWrapper.GetProject(vcsServer, trackPath, localProjectPath, item.TimeStamp); Log.Message($"git stage {localCommit.Track.ProjectPath}"); gitWrapper.Stage(localCommit.Track.ProjectPath); string author = CalcAuthor(localCommit, defaultUser); var comment = CalcComment(localCommit, author, token); User user = users.GetUser(author); try { gitWrapper.Commit(comment.ToString(), user, localCommit.TimeStamp, false); last = gitWrapper.FindCommit(x => true); hasModifications = true; } catch (Exception) { Log.Message($"Empty commit detected for {localCommit.Author} {localCommit.TimeStamp}."); } } if (hasModifications) { gitWrapper.PushEverything(); syncHistory.Add(last.Sha, item.TimeStamp.Ticks, token); } else { var head = syncHistory.GetHead(); syncHistory.Add(head.GitCommitSha, item.TimeStamp.Ticks, token); string author = CalcAuthor(item, defaultUser); Log.Message($"Push empty commits rejected for {author} {item.TimeStamp}."); } syncHistory.Save(); }); int i = 0; while (extractor.PerformExtraction()) Log.Message($"{++i} from {commits.Count} push to branch {branch.Name} completed."); }
static string CalcAuthor(CommitItem localCommit, User defaultUser) { string author = localCommit.Author; if (string.IsNullOrEmpty(author)) author = localCommit.Items.FirstOrDefault(x => !string.IsNullOrEmpty(x.User))?.User; if (!IsServiceUser(author, defaultUser.UserName)) return author; var comment = localCommit.Items.FirstOrDefault(x => CommentWrapper.IsAutoSyncComment(x.Comment)); if (comment == null) return author; var commentWrapper = CommentWrapper.Parse(comment.Comment); return commentWrapper.Author; }
static MergeRequestResult ProcessOpenedMergeRequest(DXVcsWrapper vcsWrapper, GitWrapper gitWrapper, GitLabWrapper gitLabWrapper, RegisteredUsers users, User defaultUser, string localGitDir, TrackBranch branch, MergeRequest mergeRequest, SyncHistoryWrapper syncHistory) { string autoSyncToken = syncHistory.CreateNewToken(); var lastHistoryItem = syncHistory.GetHead(); Log.Message($"Start merging mergerequest {mergeRequest.Title}"); Log.ResetErrorsAccumulator(); var changes = gitLabWrapper.GetMergeRequestChanges(mergeRequest).ToList(); if (changes.Count >= MaxChangesCount) { Log.Error($"Merge request contains more than {MaxChangesCount} changes and cannot be processed. Split it into smaller merge requests"); AssignBackConflictedMergeRequest(gitLabWrapper, users, mergeRequest, CalcCommentForFailedCheckoutMergeRequest(null)); return MergeRequestResult.Failed; } var genericChange = changes .Where(x => branch.TrackItems.FirstOrDefault(track => CheckItemForChangeSet(x, track)) != null) .Select(x => ProcessMergeRequestChanges(mergeRequest, x, localGitDir, branch, autoSyncToken)).ToList(); bool ignoreValidation = gitLabWrapper.ShouldIgnoreSharedFiles(mergeRequest); if (!ValidateMergeRequestChanges(gitLabWrapper, mergeRequest, ignoreValidation) || !vcsWrapper.ProcessCheckout(genericChange, ignoreValidation, branch)) { Log.Error("Merging merge request failed because failed validation."); AssignBackConflictedMergeRequest(gitLabWrapper, users, mergeRequest, CalcCommentForFailedCheckoutMergeRequest(genericChange)); vcsWrapper.ProcessUndoCheckout(genericChange); return MergeRequestResult.CheckoutFailed; } CommentWrapper comment = CalcComment(mergeRequest, branch, autoSyncToken); mergeRequest = gitLabWrapper.ProcessMergeRequest(mergeRequest, comment.ToString()); if (mergeRequest.State == "merged") { Log.Message("Merge request merged successfully."); gitWrapper.Pull(); gitWrapper.LFSPull(); var gitCommit = gitWrapper.FindCommit(x => CommentWrapper.Parse(x.Message).Token == autoSyncToken); long timeStamp = lastHistoryItem.VcsCommitTimeStamp; if (gitCommit != null && vcsWrapper.ProcessCheckIn(genericChange, comment.ToString())) { var checkinHistory = vcsWrapper.GenerateHistory(branch, new DateTime(timeStamp)).Where(x => x.ActionDate.Ticks > timeStamp); var lastCommit = checkinHistory.OrderBy(x => x.ActionDate).LastOrDefault(); long newTimeStamp = lastCommit?.ActionDate.Ticks ?? timeStamp; var mergeRequestResult = MergeRequestResult.Success; if (!ValidateMergeRequest(vcsWrapper, branch, lastHistoryItem, defaultUser)) mergeRequestResult = MergeRequestResult.Mixed; if (!ValidateChangeSet(genericChange)) mergeRequestResult = MergeRequestResult.Mixed; syncHistory.Add(gitCommit.Sha, newTimeStamp, autoSyncToken, mergeRequestResult == MergeRequestResult.Success ? SyncHistoryStatus.Success : SyncHistoryStatus.Mixed); syncHistory.Save(); Log.Message("Merge request checkin successfully."); return mergeRequestResult; } Log.Error("Merge request checkin failed."); if (gitCommit == null) Log.Error($"Can`t find git commit with token {autoSyncToken}"); var failedHistory = vcsWrapper.GenerateHistory(branch, new DateTime(timeStamp)); var lastFailedCommit = failedHistory.OrderBy(x => x.ActionDate).LastOrDefault(); syncHistory.Add(gitCommit.Sha, lastFailedCommit?.ActionDate.Ticks ?? timeStamp, autoSyncToken, SyncHistoryStatus.Failed); syncHistory.Save(); return MergeRequestResult.Failed; } Log.Message($"Merge request merging failed due conflicts. Resolve conflicts manually."); vcsWrapper.ProcessUndoCheckout(genericChange); AssignBackConflictedMergeRequest(gitLabWrapper, users, mergeRequest, CalcCommentForFailedCheckoutMergeRequest(genericChange)); return MergeRequestResult.Conflicts; }
static ProcessHistoryResult ProcessHistory(DXVcsWrapper vcsWrapper, GitWrapper gitWrapper, RegisteredUsers users, User defaultUser, string gitRepoPath, string localGitDir, TrackBranch branch, int commitsCount, SyncHistoryWrapper syncHistory, bool mergeCommits) { IList<CommitItem> commits = GenerateCommits(vcsWrapper, branch, syncHistory, mergeCommits); if (commits.Count > commitsCount) { Log.Message($"Commits generated. First {commitsCount} of {commits.Count} commits taken."); commits = commits.Take(commitsCount).ToList(); } else { Log.Message($"Commits generated. {commits.Count} commits taken."); } if (commits.Count > 0) ProcessHistoryInternal(vcsWrapper, gitWrapper, users, defaultUser, localGitDir, branch, commits, syncHistory); Log.Message($"Importing history from vcs completed."); return commits.Count > commitsCount ? ProcessHistoryResult.NotEnough : ProcessHistoryResult.Success; }
static MergeRequestResult ProcessMergeRequest(DXVcsWrapper vcsWrapper, GitWrapper gitWrapper, GitLabWrapper gitLabWrapper, RegisteredUsers users, User defaultUser, string localGitDir, TrackBranch branch, MergeRequest mergeRequest, SyncHistoryWrapper syncHistory) { switch (mergeRequest.State) { case "reopened": case "opened": return ProcessOpenedMergeRequest(vcsWrapper, gitWrapper, gitLabWrapper, users, defaultUser, localGitDir, branch, mergeRequest, syncHistory); } return MergeRequestResult.InvalidState; }
static bool ValidateMergeRequest(DXVcsWrapper vcsWrapper, TrackBranch branch, SyncHistoryItem previous, User defaultUser) { var history = vcsWrapper.GenerateHistory(branch, new DateTime(previous.VcsCommitTimeStamp)).Where(x => x.ActionDate.Ticks > previous.VcsCommitTimeStamp); if (history.Any(x => x.User != defaultUser.UserName)) return false; return true; }
static int ProcessMergeRequests(DXVcsWrapper vcsWrapper, GitWrapper gitWrapper, GitLabWrapper gitLabWrapper, RegisteredUsers users, User defaultUser, string gitRepoPath, string localGitDir, string branchName, string tracker, SyncHistoryWrapper syncHistory, string userName) { var project = gitLabWrapper.FindProject(gitRepoPath); TrackBranch branch = GetBranch(branchName, tracker, vcsWrapper); if (branch == null) { Log.Error($"Specified branch {branchName} not found in track file."); return 1; } var mergeRequests = GetMergeRequests(gitLabWrapper, branchName, userName, project); if (!mergeRequests.Any()) { Log.Message("Zero registered merge requests."); return 0; } int result = 0; foreach (var mergeRequest in mergeRequests) { var mergeRequestResult = ProcessMergeRequest(vcsWrapper, gitWrapper, gitLabWrapper, users, defaultUser, localGitDir, branch, mergeRequest, syncHistory); if (mergeRequestResult == MergeRequestResult.Failed) return 1; if (mergeRequestResult == MergeRequestResult.CheckoutFailed || mergeRequestResult == MergeRequestResult.Conflicts || mergeRequestResult == MergeRequestResult.InvalidState) result = 1; } return result; }
static CheckMergeChangesResult CheckChangesForMerging(GitLabWrapper gitLabWrapper, string gitRepoPath, string branchName, SyncHistoryItem head, DXVcsWrapper vcsWrapper, TrackBranch branch, SyncHistoryWrapper syncHistory, User defaultUser) { var project = gitLabWrapper.FindProject(gitRepoPath); if (project == null) { Log.Error($"Can`t find git project {gitRepoPath}"); return CheckMergeChangesResult.Error; } var gitlabBranch = gitLabWrapper.GetBranches(project).Single(x => x.Name == branchName); if (gitlabBranch.Commit.Id.Equals(new Sha1(head.GitCommitSha))) { var commits = GenerateCommits(vcsWrapper, branch, syncHistory, false); if (commits.Count == 0) { var mergeRequests = GetMergeRequests(gitLabWrapper, branchName, defaultUser.UserName, project); if (!mergeRequests.Any()) { Log.Message("Zero registered merge requests."); return CheckMergeChangesResult.NoChanges; } } } return CheckMergeChangesResult.HasChanges; }