diff --git a/src/main/java/net/geedge/asw/module/app/service/IGitService.java b/src/main/java/net/geedge/asw/module/app/service/IGitService.java index b7eaa8e..939ceda 100644 --- a/src/main/java/net/geedge/asw/module/app/service/IGitService.java +++ b/src/main/java/net/geedge/asw/module/app/service/IGitService.java @@ -1,5 +1,6 @@ package net.geedge.asw.module.app.service; +import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.lib.ObjectId; @@ -11,6 +12,8 @@ import java.util.Map; public interface IGitService { + Git getGitInstance(String workspaceId); + Repository initRepository(String workspaceId); Map infoCommit(String workspaceId, String commitId); @@ -29,9 +32,11 @@ public interface IGitService { String getLatestCommitId(String workspaceId, String branch); + ObjectId insertBlobFileToDatabase(Repository repository, byte[] data) throws IOException; + List> getDiffFileListInCommits(String workspaceId, String newCommitId, String oldCommitId); - String mergeBranch(String workspaceId, String sourceBranch, String targetBranch, String message) throws RuntimeException; + String mergeBranch(String workspaceId, String sourceBranch, String targetBranch, String message, List> resolveConflictFileContent) throws RuntimeException; List> listApplication(String workspaceId, String branch, String q); @@ -53,8 +58,6 @@ public interface IGitService { List> getConflictFileInfoInBranches(String workspaceId, String srcBranch, String tgtBranch); - void resolveMrConflicts(String workspaceId, String srcBranch, String tgtBranch, String commitId, String commitMessage, List> files); - boolean commitIndex(Repository repo, String branch, DirCache index, ObjectId parentId1, ObjectId parentId2, String message) throws IOException, ConcurrentRefUpdateException; } diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationMergeServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationMergeServiceImpl.java index 115f454..700d5c5 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationMergeServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationMergeServiceImpl.java @@ -211,7 +211,8 @@ public class ApplicationMergeServiceImpl extends ServiceImpl> files = T.MapUtil.get(body, "files", List.class, new ArrayList()); - gitService.resolveMrConflicts(workspaceId, sourceBranch, targetBranch, commitId, commitMessage, files); + // 反过来合并 + gitService.mergeBranch(workspaceId, targetBranch, sourceBranch, commitMessage, files); } /** @@ -241,7 +242,7 @@ public class ApplicationMergeServiceImpl extends ServiceImpl> resolveConflictFileContent) throws RuntimeException { log.info("[mergeBranch] [begin] [workspaceId: {}] [srcBranch: {}] [tgtBranch: {}]", workspaceId, srcBranch, tgtBranch); // prepare a new folder for the cloned repository File localPath = T.FileUtil.file(net.geedge.asw.common.util.Constants.TEMP_PATH, T.StrUtil.uuid()); @@ -475,29 +478,51 @@ public class GitServiceImpl implements IGitService { .call(); MergeResult.MergeStatus mergeStatus = mergeResult.getMergeStatus(); - if (mergeStatus.isSuccessful()) { - log.info("[mergeBranch] [merge success]"); - - // push - Iterable pushResultIterable = git.push() - .setRemote("origin") - .add(tgtBranch) - .call(); - for (PushResult pushResult : pushResultIterable) { - for (RemoteRefUpdate update : pushResult.getRemoteUpdates()) { - if (update.getStatus() != RemoteRefUpdate.Status.OK && update.getStatus() != RemoteRefUpdate.Status.UP_TO_DATE) { - log.error("[mergeBranch] [push error] [remote: {}] [status: {}]", update.getRemoteName(), update.getStatus()); - String errorMessage = "Push failed: " + update.getStatus(); - throw new RuntimeException(errorMessage); + log.info("[mergeBranch] [merge status: {}]", mergeStatus); + if (!mergeStatus.isSuccessful()) { + // 解决冲突 + if (mergeStatus == MergeResult.MergeStatus.CONFLICTING && T.CollUtil.isNotEmpty(resolveConflictFileContent)) { + Map conflicts = mergeResult.getConflicts(); + for (Map.Entry entry : conflicts.entrySet()) { + String conflictFilePath = entry.getKey(); + Map map = resolveConflictFileContent.stream() + .filter(m -> T.StrUtil.equals(conflictFilePath, T.MapUtil.getStr(m, "path"))) + .findFirst() + .orElse(null); + if (null != map) { + Path filePath = Paths.get(localPath.getAbsolutePath(), conflictFilePath); + Files.write(filePath, T.MapUtil.getStr(map, "content").getBytes(StandardCharsets.UTF_8)); + git.add().addFilepattern(conflictFilePath).call(); } } + git.commit().setMessage(message).call(); + } else { + // 其他类型的合并错误,抛出异常 + String errorMessage = String.format("Merge failed: %s, Conflicts: %s", mergeStatus, mergeResult.getConflicts()); + throw new RuntimeException(errorMessage); } - return mergeResult.getNewHead().getName(); - } else { - log.error("[mergeBranch] [merge failed] [mergeStatus: {}] [conflict: {}]", mergeStatus, T.JSONUtil.toJsonStr(mergeResult.getConflicts())); - String errorMessage = String.format("Merge failed: %s, Conflicts: %s", mergeStatus, T.JSONUtil.toJsonStr(mergeResult.getConflicts())); - throw new RuntimeException(errorMessage); } + + // push + Iterable pushResultIterable = git.push() + .setRemote("origin") + .add(tgtBranch) + .call(); + for (PushResult pushResult : pushResultIterable) { + for (RemoteRefUpdate update : pushResult.getRemoteUpdates()) { + if (update.getStatus() != RemoteRefUpdate.Status.OK && update.getStatus() != RemoteRefUpdate.Status.UP_TO_DATE) { + log.error("[mergeBranch] [push error] [remote: {}] [status: {}]", update.getRemoteName(), update.getStatus()); + String errorMessage = "Push failed: " + update.getStatus(); + throw new RuntimeException(errorMessage); + } + } + } + + if (null != mergeResult.getNewHead()) { + return mergeResult.getNewHead().getName(); + } + // 解决冲突合并的情况下无法从 mergeResult 中获取提交信息,查询最新提交信息返回 + return this.getLatestCommitId(workspaceId, srcBranch); } catch (Exception e) { log.error(e, "[mergeBranch] [error] [workspaceId: {}]", workspaceId); throw new RuntimeException(e.getMessage()); @@ -1072,7 +1097,8 @@ public class GitServiceImpl implements IGitService { * @return * @throws IOException */ - private ObjectId insertBlobFileToDatabase(Repository repository, byte[] data) throws IOException { + @Override + public ObjectId insertBlobFileToDatabase(Repository repository, byte[] data) throws IOException { try (ObjectInserter inserter = repository.getObjectDatabase().newInserter()) { ObjectId blobId = inserter.insert(Constants.OBJ_BLOB, data); inserter.flush(); @@ -1201,58 +1227,58 @@ public class GitServiceImpl implements IGitService { * @param commitMessage * @param files */ - @Override - public void resolveMrConflicts(String workspaceId, String srcBranch, String tgtBranch, String commitId, String commitMessage, List> files) { - try (Git git = this.getGitInstance(workspaceId); - Repository repository = git.getRepository(); - TreeWalk treeWalk = new TreeWalk(repository); - RevWalk revWalk = new RevWalk(repository)) { - - ObjectId srcBranchLatestCommitId = repository.resolve(srcBranch); - - // branch tree - treeWalk.addTree(revWalk.parseTree(srcBranchLatestCommitId)); - treeWalk.setRecursive(true); - - DirCache newTree = DirCache.newInCore(); - DirCacheBuilder newTreeBuilder = newTree.builder(); - - List updateFilePath = files.stream().map(map -> T.MapUtil.getStr(map, "path")).collect(Collectors.toList()); - while (treeWalk.next()) { - String pathString = treeWalk.getPathString(); - // 先删 - if (!updateFilePath.contains(pathString)) { - DirCacheEntry entry = new DirCacheEntry(pathString); - entry.setFileMode(treeWalk.getFileMode(0)); - entry.setObjectId(treeWalk.getObjectId(0)); - newTreeBuilder.add(entry); - } - } - // 后增 - for (Map map : files) { - String path = T.MapUtil.getStr(map, "path"); - DirCacheEntry dirCacheEntry = new DirCacheEntry(path); - dirCacheEntry.setFileMode(FileMode.REGULAR_FILE); - - String content = T.MapUtil.getStr(map, "content"); - ObjectId objectId = this.insertBlobFileToDatabase(repository, content.getBytes()); - dirCacheEntry.setObjectId(objectId); - newTreeBuilder.add(dirCacheEntry); - } - newTreeBuilder.finish(); - - // merge commit - ObjectId parentId1 = ObjectId.fromString(commitId); - RevCommit revCommit = revWalk.parseCommit(repository.resolve(tgtBranch)); - ObjectId parentId2 = revCommit.getId(); - - boolean success = this.commitIndex(repository, srcBranch, newTree, parentId1, parentId2, commitMessage); - log.info("[resolveMrConflicts] [workspaceId: {}] [srcBranch: {}] [tgtBranch: {}] [commitId: {}] [success: {}]", workspaceId, srcBranch, tgtBranch, commitId, success); - } catch (IOException | ConcurrentRefUpdateException e) { - log.error(e, "[resolveMrConflicts] [error] [workspaceId: {}] [srcBranch: {}] [tgtBranch: {}] [commitId: {}]", workspaceId, srcBranch, tgtBranch, commitId); - throw new RuntimeException(e); - } - } +// @Override +// public void resolveMrConflicts(String workspaceId, String srcBranch, String tgtBranch, String commitId, String commitMessage, List> files) { +// try (Git git = this.getGitInstance(workspaceId); +// Repository repository = git.getRepository(); +// TreeWalk treeWalk = new TreeWalk(repository); +// RevWalk revWalk = new RevWalk(repository)) { +// +// ObjectId srcBranchLatestCommitId = repository.resolve(srcBranch); +// +// // branch tree +// treeWalk.addTree(revWalk.parseTree(srcBranchLatestCommitId)); +// treeWalk.setRecursive(true); +// +// DirCache newTree = DirCache.newInCore(); +// DirCacheBuilder newTreeBuilder = newTree.builder(); +// +// List updateFilePath = files.stream().map(map -> T.MapUtil.getStr(map, "path")).collect(Collectors.toList()); +// while (treeWalk.next()) { +// String pathString = treeWalk.getPathString(); +// // 先删 +// if (!updateFilePath.contains(pathString)) { +// DirCacheEntry entry = new DirCacheEntry(pathString); +// entry.setFileMode(treeWalk.getFileMode(0)); +// entry.setObjectId(treeWalk.getObjectId(0)); +// newTreeBuilder.add(entry); +// } +// } +// // 后增 +// for (Map map : files) { +// String path = T.MapUtil.getStr(map, "path"); +// DirCacheEntry dirCacheEntry = new DirCacheEntry(path); +// dirCacheEntry.setFileMode(FileMode.REGULAR_FILE); +// +// String content = T.MapUtil.getStr(map, "content"); +// ObjectId objectId = this.insertBlobFileToDatabase(repository, content.getBytes()); +// dirCacheEntry.setObjectId(objectId); +// newTreeBuilder.add(dirCacheEntry); +// } +// newTreeBuilder.finish(); +// +// // merge commit +// ObjectId parentId1 = ObjectId.fromString(commitId); +// RevCommit revCommit = revWalk.parseCommit(repository.resolve(tgtBranch)); +// ObjectId parentId2 = revCommit.getId(); +// +// boolean success = this.commitIndex(repository, srcBranch, newTree, parentId1, parentId2, commitMessage); +// log.info("[resolveMrConflicts] [workspaceId: {}] [srcBranch: {}] [tgtBranch: {}] [commitId: {}] [success: {}]", workspaceId, srcBranch, tgtBranch, commitId, success); +// } catch (IOException | ConcurrentRefUpdateException e) { +// log.error(e, "[resolveMrConflicts] [error] [workspaceId: {}] [srcBranch: {}] [tgtBranch: {}] [commitId: {}]", workspaceId, srcBranch, tgtBranch, commitId); +// throw new RuntimeException(e); +// } +// } /** * commit @@ -1326,6 +1352,7 @@ public class GitServiceImpl implements IGitService { * @throws IOException * @throws ConcurrentRefUpdateException */ + @Override public boolean commitIndex(Repository repo, String branch, DirCache index, ObjectId parentId1, ObjectId parentId2, String message) throws IOException, ConcurrentRefUpdateException { boolean success = false; try (ObjectInserter odi = repo.newObjectInserter()) {