diff --git a/pom.xml b/pom.xml index fedbab4..35bc7a9 100644 --- a/pom.xml +++ b/pom.xml @@ -179,6 +179,13 @@ 2.12.0 + + + org.eclipse.jgit + org.eclipse.jgit + 7.0.0.202409031743-r + + diff --git a/src/main/java/net/geedge/asw/module/app/controller/GitController.java b/src/main/java/net/geedge/asw/module/app/controller/GitController.java new file mode 100644 index 0000000..a2719b9 --- /dev/null +++ b/src/main/java/net/geedge/asw/module/app/controller/GitController.java @@ -0,0 +1,52 @@ +package net.geedge.asw.module.app.controller; + +import net.geedge.asw.common.util.ASWException; +import net.geedge.asw.common.util.R; +import net.geedge.asw.common.util.RCode; +import net.geedge.asw.common.util.T; +import net.geedge.asw.module.app.service.IGitService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/api/v1/workspace") +public class GitController { + + @Autowired + private IGitService gitService; + + @GetMapping("/{workspaceId}/branch") + public R listBranch(@PathVariable("workspaceId") String workspaceId, + @RequestParam(value = "search", required = false) String search) { + List> list = gitService.listBranch(workspaceId, search); + return R.ok().putData("record", list); + } + + @GetMapping("/{workspaceId}/branch/{branchName}") + public R infoBranch(@PathVariable("workspaceId") String workspaceId, @PathVariable("branchName") String branchName) { + Map record = gitService.infoBranch(workspaceId, branchName); + return R.ok().putData("record", record); + } + + @PostMapping("/{workspaceId}/branch") + public R newBranch(@PathVariable("workspaceId") String workspaceId, @RequestBody Map requestBody) { + String branch = T.MapUtil.getStr(requestBody, "branch", ""); + String ref = T.MapUtil.getStr(requestBody, "ref", ""); + if (T.StrUtil.hasEmpty(branch, ref)) { + throw new ASWException(RCode.PARAM_CANNOT_EMPTY); + } + + Map record = gitService.newBranch(workspaceId, branch, ref); + return R.ok().putData("record", record); + } + + @DeleteMapping("/{workspaceId}/branch/{branchName}") + public R deleteBranch(@PathVariable("workspaceId") String workspaceId, @PathVariable("branchName") String branchName) { + gitService.deleteBranch(workspaceId, branchName); + return R.ok(); + } + +} \ No newline at end of file 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 new file mode 100644 index 0000000..1ec819c --- /dev/null +++ b/src/main/java/net/geedge/asw/module/app/service/IGitService.java @@ -0,0 +1,16 @@ +package net.geedge.asw.module.app.service; + +import java.util.List; +import java.util.Map; + +public interface IGitService { + + List> listBranch(String workspaceId, String search); + + Map infoBranch(String workspaceId, String branchName); + + Map newBranch(String workspaceId, String branchName, String ref); + + void deleteBranch(String workspaceId, String branchName); + +} diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/GitServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/GitServiceImpl.java new file mode 100644 index 0000000..6110b96 --- /dev/null +++ b/src/main/java/net/geedge/asw/module/app/service/impl/GitServiceImpl.java @@ -0,0 +1,182 @@ +package net.geedge.asw.module.app.service.impl; + +import cn.hutool.log.Log; +import net.geedge.asw.common.util.ASWException; +import net.geedge.asw.common.util.RCode; +import net.geedge.asw.common.util.T; +import net.geedge.asw.module.app.service.IGitService; +import net.geedge.asw.module.workspace.entity.WorkspaceEntity; +import net.geedge.asw.module.workspace.service.IWorkspaceService; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class GitServiceImpl implements IGitService { + + private final static Log log = Log.get(); + + /** + * 本地分支引用前缀 + */ + public static final String LOCAL_BRANCH_PREFIX = "refs/heads/"; + + @Autowired + private IWorkspaceService workspaceService; + + /** + * get repository path + * path= {webRootPath}/workspeace/{workspace.name} + */ + private File getRepoDirPath(String workspaceId) { + WorkspaceEntity workspace = workspaceService.getById(workspaceId); + File repoDir = T.FileUtil.file(T.WebPathUtil.getRootPath(), "workspeace", workspace.getName()); + return repoDir; + } + + /** + * get git instance + */ + private Git getGitInstance(File repoDir) { + try { + if (T.FileUtil.exist(repoDir) && T.FileUtil.file(repoDir, ".git").exists()) { + log.info("[getGitInstance] [open exist repository] [path: {}]", repoDir); + + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + builder.setGitDir(T.FileUtil.file(repoDir, ".git")); + builder.readEnvironment(); + builder.findGitDir(); + + return new Git(builder.build()); + } else { + log.info("[getGitInstance] [init new repository] [path: {}]", repoDir); + // init + Git git = Git.init().setDirectory(repoDir).call(); + // config + StoredConfig config = git.getRepository().getConfig(); + config.setString("user", null, "name", "asw"); + config.setString("user", null, "email", "asw@geedgenetworks.com"); + config.save(); + return git; + } + } catch (IOException | GitAPIException | IllegalStateException e) { + log.error(e, "[getGitInstance] [error] [path: {}]", repoDir); + throw new RuntimeException(e); + } + } + + @Override + public List> listBranch(String workspaceId, String search) { + List> resultList = T.ListUtil.list(true); + + File repoDir = this.getRepoDirPath(workspaceId); + try (Git git = this.getGitInstance(repoDir)) { +// List call = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call(); + + // 默认行为,进查询本地分支 + List call = git.branchList().call(); + RevWalk revCommits = new RevWalk(git.getRepository()); + + for (Ref ref : call) { + String branchName = ref.getName(); + // 返回时去掉前缀 + branchName = branchName.replaceAll(LOCAL_BRANCH_PREFIX, ""); + if (T.StrUtil.isNotEmpty(search)) { + if (!T.StrUtil.contains(branchName, search)) { + continue; + } + } + + Map m = T.MapUtil.builder() + .put("name", branchName) + .build(); + + RevCommit commit = revCommits.parseCommit(ref.getObjectId()); + List parentIds = Arrays.stream(commit.getParents()).map(RevCommit::getName).collect(Collectors.toList()); + + Map m1 = new LinkedHashMap<>(); + m1.put("id", commit.getName()); + m1.put("shortId", T.StrUtil.subPre(commit.getName(), 8)); + m1.put("createdAt", commit.getCommitTime()); + + m1.put("title", commit.getShortMessage()); + m1.put("message", commit.getFullMessage()); + m1.put("parentIds", parentIds); + + PersonIdent authorIdent = commit.getAuthorIdent(); + m1.put("authorName", authorIdent.getName()); + m1.put("authorEmail", authorIdent.getEmailAddress()); + m1.put("authoredDate", authorIdent.getWhen().getTime()); + + PersonIdent committerIdent = commit.getCommitterIdent(); + m1.put("committerName", committerIdent.getName()); + m1.put("committerEmail", committerIdent.getEmailAddress()); + m1.put("committedDate", committerIdent.getWhen().getTime()); + + m.put("commit", m1); + resultList.add(m); + } + } catch (GitAPIException | IOException e) { + log.error(e, "[listBranch] [error] [workspaceId: {}]", workspaceId); + throw new ASWException(RCode.ERROR); + } + return resultList; + } + + @Override + public Map infoBranch(String workspaceId, String branchName) { + List> listBranch = this.listBranch(workspaceId, branchName); + + // 分支不存在 + if (T.CollUtil.isEmpty(listBranch)) { + throw new ASWException(RCode.SYS_RECORD_NOT_FOUND); + } + return T.CollUtil.getFirst(listBranch); + } + + @Override + public Map newBranch(String workspaceId, String branchName, String ref) { + File repoDir = this.getRepoDirPath(workspaceId); + try (Git git = this.getGitInstance(repoDir)) { + git.branchCreate() + .setName(branchName) + .setStartPoint(ref) + .call(); + + return this.infoBranch(workspaceId, branchName); + } catch (GitAPIException e) { + log.error(e, "[newBranch] [error] [workspaceId: {}] [branchName: {}] [ref: {}]", workspaceId, branchName, ref); + throw new ASWException(RCode.ERROR); + } + } + + @Override + public void deleteBranch(String workspaceId, String branchName) { + File repoDir = this.getRepoDirPath(workspaceId); + try (Git git = this.getGitInstance(repoDir)) { + git.branchDelete() + .setBranchNames(branchName) + .call(); + } catch (GitAPIException e) { + log.error(e, "[deleteBranch] [error] [workspaceId: {}] [branchName: {}]", workspaceId, branchName); + throw new ASWException(RCode.ERROR); + } + } + +} \ No newline at end of file