feat: ASW-88 本地 GIT 仓库管理 application 文件

1. 使用 JGIT 完成对 application 文件的操作
This commit is contained in:
shizhendong
2024-10-16 16:13:56 +08:00
parent dc5f2ebb74
commit 938925e76c
5 changed files with 626 additions and 46 deletions

View File

@@ -57,6 +57,10 @@ public enum RCode {
PACKAGE_DESCRIPTION_CANNOT_EMPTY(202002, "package description cannot be empty"),
// GIT
GIT_COMMIT_CONFLICT_ERROR(203001, "Commit failed; fix conflicts and then commit the result"),
// Runner
RUNNER_ID_CANNOT_EMPTY(301001, "runner id cannot be empty"),

View File

@@ -49,4 +49,88 @@ public class GitController {
return R.ok();
}
@GetMapping("/{workspaceId}/branch/{branchName}/application")
public R listApplication(@PathVariable("workspaceId") String workspaceId,
@PathVariable("branchName") String branchName,
@RequestParam(value = "q", required = false) String q) {
List<Map<Object, Object>> records = gitService.listApplication(workspaceId, branchName, q);
return R.ok().putData("records", records);
}
@GetMapping("/{workspaceId}/branch/{branchName}/application/{applicationName}")
public R infoApplication(@PathVariable("workspaceId") String workspaceId,
@PathVariable("branchName") String branchName,
@PathVariable("applicationName") String applicationName) {
Map<Object, Object> record = gitService.infoApplication(workspaceId, branchName, applicationName);
return R.ok().putData("record", record);
}
@PostMapping("/{workspaceId}/branch/{branchName}/application")
public synchronized R newApplication(@PathVariable("workspaceId") String workspaceId,
@PathVariable("branchName") String branchName,
@RequestBody Map<String, String> body) {
String applicationName = T.MapUtil.getStr(body, "name");
T.VerifyUtil.is(applicationName).notEmpty(RCode.PARAM_CANNOT_EMPTY);
gitService.newApplication(workspaceId, branchName, applicationName);
return R.ok();
}
@PostMapping("/{workspaceId}/branch/{branchName}/application/commit")
public synchronized R updateApplication(@PathVariable("workspaceId") String workspaceId,
@PathVariable("branchName") String branchName,
@RequestBody Map<String, Object> body) {
String lastCommitId = T.MapUtil.getStr(body, "lastCommitId");
String message = T.MapUtil.getStr(body, "message");
T.VerifyUtil.is(lastCommitId).notEmpty(RCode.PARAM_CANNOT_EMPTY)
.and(message).notEmpty(RCode.PARAM_CANNOT_EMPTY);
List<Map<String, String>> files = T.MapUtil.get(body, "files", List.class, T.ListUtil.list(true));
if (T.CollUtil.isEmpty(files)) {
return R.ok();
}
for (Map<String, String> file : files) {
String action = T.MapUtil.getStr(file, "action");
String path = T.MapUtil.getStr(file, "path");
String content = T.MapUtil.getStr(file, "content");
if (T.StrUtil.hasEmpty(action, path, content)) {
return R.error(RCode.PARAM_CANNOT_EMPTY);
}
}
gitService.updateApplication(workspaceId, branchName, lastCommitId, message, files);
return R.ok();
}
@DeleteMapping("/{workspaceId}/branch/{branchName}/application/{applicationName}")
public synchronized R deleteApplication(@PathVariable("workspaceId") String workspaceId,
@PathVariable("branchName") String branchName,
@PathVariable("applicationName") String applicationName) {
gitService.deleteApplication(workspaceId, branchName, applicationName);
return R.ok();
}
@GetMapping("/{workspaceId}/branch/{branchName}/application/{applicationName}/commit")
public R listApplicationCommit(@PathVariable("workspaceId") String workspaceId,
@PathVariable("branchName") String branchName,
@PathVariable("applicationName") String applicationName,
@RequestParam(required = false) String file) {
List<Map<Object, Object>> records = gitService.listApplicationCommit(workspaceId, branchName, applicationName, file);
return R.ok().putData("records", records);
}
@GetMapping("/{workspaceId}/branch/{branchName}/application/{applicationName}/commit/{commitId}/content")
public R infoApplicationFileContent(@PathVariable("workspaceId") String workspaceId,
@PathVariable("branchName") String branchName,
@PathVariable("applicationName") String applicationName,
@PathVariable("commitId") String commitId,
@RequestParam(required = true) String file) {
Map<Object, Object> record = gitService.infoApplicationFileContent(workspaceId, branchName, applicationName, commitId, file);
return R.ok().putData("record", record);
}
}

View File

@@ -13,4 +13,18 @@ public interface IGitService {
void deleteBranch(String workspaceId, String branchName);
List<Map<Object, Object>> listApplication(String workspaceId, String branch, String q);
Map<Object, Object> infoApplication(String workspaceId, String branch, String applicationName);
void newApplication(String workspaceId, String branch, String applicationName);
void deleteApplication(String workspaceId, String branch, String applicationName);
void updateApplication(String workspaceId, String branch, String lastCommitId, String message, List<Map<String, String>> updateContent);
List<Map<Object, Object>> listApplicationCommit(String workspaceId, String branch, String applicationName, String file);
Map<Object, Object> infoApplicationFileContent(String workspaceId, String branch, String applicationName, String commitId, String file);
}

View File

@@ -1,30 +1,37 @@
package net.geedge.asw.module.app.service.impl;
import cn.dev33.satoken.stp.StpUtil;
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.sys.entity.SysUserEntity;
import net.geedge.asw.module.sys.service.ISysUserService;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
import net.geedge.asw.module.workspace.service.IWorkspaceService;
import org.apache.commons.io.FilenameUtils;
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.diff.DiffEntry;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Service
@@ -32,14 +39,32 @@ public class GitServiceImpl implements IGitService {
private final static Log log = Log.get();
@Value("${file.extensions.text:txt,csv,md,html,xml,json,log,bat,py,sh,ini,conf,yaml,yml,properties,toml,java,c,cpp,js,php,ts,go,rb,rtf,tex,rss,xhtml,sql}")
private String textExtensions;
/**
* 本地分支引用前缀
*/
public static final String LOCAL_BRANCH_PREFIX = "refs/heads/";
@Autowired
private ISysUserService userService;
@Autowired
private IWorkspaceService workspaceService;
/**
* is binary file
*
* @param filename
* @return
*/
private boolean isBinary(String filename) {
String extension = FilenameUtils.getExtension(filename);
List<String> split = T.StrUtil.split(this.textExtensions, ",");
return !split.contains(extension.toLowerCase());
}
/**
* get repository path
* path= {webRootPath}/workspeace/{workspace.name}
@@ -53,29 +78,34 @@ public class GitServiceImpl implements IGitService {
/**
* get git instance
*/
private Git getGitInstance(File repoDir) {
public Git getGitInstance(File repoDir) {
try {
if (T.FileUtil.exist(repoDir) && T.FileUtil.file(repoDir, ".git").exists()) {
log.info("[getGitInstance] [open exist repository] [path: {}]", repoDir);
// 目录不存在,初始化裸仓库
if (!repoDir.exists()) {
log.info("[getGitInstance] [dir not exist] [init new repository] [path: {}]", repoDir);
return Git.init()
.setBare(true)
.setDirectory(repoDir)
.call();
}
FileRepositoryBuilder builder = new FileRepositoryBuilder();
builder.setGitDir(T.FileUtil.file(repoDir, ".git"));
builder.readEnvironment();
builder.findGitDir();
FileRepositoryBuilder builder = new FileRepositoryBuilder();
Repository repository = builder.setGitDir(repoDir)
.readEnvironment()
.findGitDir()
.build();
return new Git(builder.build());
// 是否为 Git 仓库
if (repository.getObjectDatabase().exists()) {
return new Git(repository);
} 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;
return Git.init()
.setBare(true)
.setDirectory(repoDir)
.call();
}
} catch (IOException | GitAPIException | IllegalStateException e) {
} catch (GitAPIException | IOException e) {
log.error(e, "[getGitInstance] [error] [path: {}]", repoDir);
throw new RuntimeException(e);
}
@@ -108,28 +138,8 @@ public class GitServiceImpl implements IGitService {
.build();
RevCommit commit = revCommits.parseCommit(ref.getObjectId());
List<String> parentIds = Arrays.stream(commit.getParents()).map(RevCommit::getName).collect(Collectors.toList());
m.put("commit", this.buildAswCommitInfo(commit));
Map<Object, Object> 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) {
@@ -179,4 +189,468 @@ public class GitServiceImpl implements IGitService {
}
}
@Override
public List<Map<Object, Object>> listApplication(String workspaceId, String branch, String q) {
List<Map<Object, Object>> resultList = T.ListUtil.list(true);
File repoDir = this.getRepoDirPath(workspaceId);
try (Git git = this.getGitInstance(repoDir)) {
Repository repository = git.getRepository();
try (TreeWalk treeWalk = new TreeWalk(repository);
RevWalk revWalk = new RevWalk(repository)) {
ObjectId branchRef = repository.resolve(branch);
treeWalk.addTree(revWalk.parseTree(branchRef));
treeWalk.setFilter(PathFilter.create("applications/"));
treeWalk.setRecursive(true);
while (treeWalk.next()) {
String fileName = treeWalk.getNameString();
if (T.StrUtil.equals("basic.json", fileName)) {
ObjectLoader loader = repository.open(treeWalk.getObjectId(0));
String basicJsonStr = T.StrUtil.utf8Str(loader.getBytes());
basicJsonStr = T.StrUtil.emptyToDefault(basicJsonStr, T.StrUtil.EMPTY_JSON);
Map basicJsonMap = T.JSONUtil.toBean(basicJsonStr, Map.class);
Map<Object, Object> m = T.MapUtil.newHashMap(true);
m.putAll(basicJsonMap);
Iterable<RevCommit> iterable = git.log()
.add(branchRef)
.addPath(treeWalk.getPathString().replaceAll(fileName, ""))
.call();
Iterator<RevCommit> iterator = iterable.iterator();
RevCommit commit = iterator.hasNext() ? iterator.next() : null;
m.put("commit", this.buildAswCommitInfo(commit));
resultList.add(m);
}
}
}
} catch (IOException | GitAPIException e) {
log.error(e, "[listApplication] [error] [workspaceId: {}] [branch: {}]", workspaceId, branch);
throw new ASWException(RCode.ERROR);
}
return resultList;
}
@Override
public Map<Object, Object> infoApplication(String workspaceId, String branch, String applicationName) {
Map<Object, Object> result = T.MapUtil.builder()
.put("branch", branch)
.build();
File repoDir = this.getRepoDirPath(workspaceId);
try (Git git = this.getGitInstance(repoDir)) {
Repository repository = git.getRepository();
// 获取指定版本的最新ID
ObjectId branchRef = repository.resolve(branch);
result.put("commitId", branchRef.getName());
List<Object> files = T.ListUtil.list(true);
try (TreeWalk treeWalk = new TreeWalk(repository);
RevWalk revWalk = new RevWalk(repository)) {
treeWalk.addTree(revWalk.parseTree(branchRef));
treeWalk.setFilter(PathFilter.create("applications/" + applicationName + "/"));
treeWalk.setRecursive(true);
while (treeWalk.next()) {
Map<Object, Object> m = T.MapUtil.builder()
.put("path", treeWalk.getPathString())
.build();
ObjectLoader loader = repository.open(treeWalk.getObjectId(0));
if (this.isBinary(treeWalk.getNameString())) {
String content = Base64.getEncoder().encodeToString(loader.getBytes());
m.put("encoding", "base64");
m.put("content", content);
} else {
m.put("encoding", "");
m.put("content", T.StrUtil.utf8Str(loader.getBytes()));
}
// lastCommitId
Iterable<RevCommit> iterable = git.log()
.add(branchRef)
.addPath(treeWalk.getPathString())
.call();
Iterator<RevCommit> iterator = iterable.iterator();
m.put("lastCommitId", iterator.hasNext() ? iterator.next().getName() : null);
files.add(m);
}
}
result.put("files", files);
} catch (IOException | GitAPIException e) {
log.error(e, "[infoApplication] [error] [workspaceId: {}] [branch: {}] [application: {}]", workspaceId, branch, applicationName);
throw new ASWException(RCode.ERROR);
}
return result;
}
@Override
public void newApplication(String workspaceId, String branch, String applicationName) {
File repoDir = this.getRepoDirPath(workspaceId);
try (Git git = this.getGitInstance(repoDir)) {
Repository repository = git.getRepository();
Map<String, ObjectId> filePathAndBlobIdMap = T.MapUtil.newHashMap(true);
for (String str : T.ListUtil.of("README.md", "basic.json", "signature.json", "icon.png")) {
String savePath = T.StrUtil.concat(true, "applications/", applicationName, "/", str);
ObjectId objectId = this.insertBlobFileToDatabase(repository, T.StrUtil.EMPTY.getBytes());
filePathAndBlobIdMap.put(savePath, objectId);
}
try (ObjectInserter inserter = repository.getObjectDatabase().newInserter();
TreeWalk treeWalk = new TreeWalk(repository);
RevWalk revWalk = new RevWalk(repository)) {
// branch tree
ObjectId resolveId = repository.resolve(branch);
if (null != resolveId) {
treeWalk.addTree(revWalk.parseTree(resolveId));
} else {
treeWalk.addTree(new CanonicalTreeParser());
}
treeWalk.setRecursive(true);
DirCache newTree = DirCache.newInCore();
DirCacheBuilder newTreeBuilder = newTree.builder();
while (treeWalk.next()) {
DirCacheEntry entry = new DirCacheEntry(treeWalk.getPathString());
entry.setFileMode(treeWalk.getFileMode(0));
entry.setObjectId(treeWalk.getObjectId(0));
newTreeBuilder.add(entry);
}
// update new tree
for (Map.Entry<String, ObjectId> entry : filePathAndBlobIdMap.entrySet()) {
String filePath = entry.getKey();
ObjectId blobId = entry.getValue();
// add file ref
DirCacheEntry dirCacheEntry = new DirCacheEntry(filePath);
dirCacheEntry.setFileMode(FileMode.REGULAR_FILE);
dirCacheEntry.setObjectId(blobId);
newTreeBuilder.add(dirCacheEntry);
}
newTreeBuilder.finish();
ObjectId newTreeId = newTree.writeTree(inserter);
String message = String.format("feat: add %s application", applicationName);
this.createCommit(repository, branch, newTreeId, message);
}
} catch (IOException e) {
log.error(e, "[newApplication] [error] [workspaceId: {}] [branch: {}] [application: {}]", workspaceId, branch, applicationName);
throw new ASWException(RCode.ERROR);
}
}
@Override
public void deleteApplication(String workspaceId, String branch, String applicationName) {
File repoDir = this.getRepoDirPath(workspaceId);
try (Git git = this.getGitInstance(repoDir)) {
Repository repository = git.getRepository();
try (ObjectInserter inserter = repository.getObjectDatabase().newInserter();
TreeWalk treeWalk = new TreeWalk(repository);
RevWalk revWalk = new RevWalk(repository)) {
ObjectId branchRef = repository.resolve(branch);
treeWalk.addTree(revWalk.parseTree(branchRef));
treeWalk.setRecursive(true);
DirCache newTree = DirCache.newInCore();
DirCacheBuilder newTreeBuilder = newTree.builder();
String appFilePrefixStr = T.StrUtil.concat(true, "applications/", applicationName, "/");
while (treeWalk.next()) {
String pathString = treeWalk.getPathString();
if (!pathString.startsWith(appFilePrefixStr)) {
DirCacheEntry entry = new DirCacheEntry(pathString);
entry.setFileMode(treeWalk.getFileMode(0));
entry.setObjectId(treeWalk.getObjectId(0));
newTreeBuilder.add(entry);
}
}
newTreeBuilder.finish();
ObjectId newTreeId = newTree.writeTree(inserter);
String message = String.format("refactor: remove %s application", applicationName);
this.createCommit(repository, branch, newTreeId, message);
}
} catch (IOException e) {
log.error(e, "[deleteApplication] [error] [workspaceId: {}] [branch: {}] [application: {}]", workspaceId, branch, applicationName);
throw new ASWException(RCode.ERROR);
}
}
@Override
public void updateApplication(String workspaceId, String branch, String lastCommitId, String message, List<Map<String, String>> updateContent) {
File repoDir = this.getRepoDirPath(workspaceId);
try (Git git = this.getGitInstance(repoDir)) {
Repository repository = git.getRepository();
// 分支最新 commitId
ObjectId branchRef = repository.resolve(branch);
// 如果不相等,检查 param.lastCommitId --- branch.HEAD 期间是否更新了本次修改文件
if (!T.StrUtil.equals(lastCommitId, branchRef.getName())) {
List<String> updateFilePath = updateContent.stream()
.filter(map -> {
String action = T.MapUtil.getStr(map, "action");
return T.StrUtil.equalsAny(action, "create", "update");
})
.map(map -> T.MapUtil.getStr(map, "path"))
.collect(Collectors.toList());
ObjectId currentCommitId = repository.resolve(lastCommitId);
try (RevWalk walk = new RevWalk(repository)) {
CanonicalTreeParser c1 = new CanonicalTreeParser();
c1.reset(repository.newObjectReader(), walk.parseCommit(currentCommitId).getTree());
CanonicalTreeParser c2 = new CanonicalTreeParser();
c2.reset(repository.newObjectReader(), walk.parseCommit(branchRef).getTree());
List<DiffEntry> diffs = git.diff()
.setOldTree(c1)
.setNewTree(c2)
.call();
List<String> affectFilePathList = diffs.stream()
.filter(entry -> T.StrUtil.equalsAnyIgnoreCase(entry.getChangeType().name(), DiffEntry.ChangeType.MODIFY.name(), DiffEntry.ChangeType.ADD.name()))
.map(DiffEntry::getNewPath)
.collect(Collectors.toList());
List<String> intersection = T.CollUtil.intersection(updateFilePath, affectFilePathList).stream().toList();
if (T.CollUtil.isEmpty(intersection)) {
// 在 param.lastCommitId 不是当前分支最新提交时,本次提交文件没有冲突,更新 commit=branch.HEAD
lastCommitId = branchRef.getName();
} else {
throw new ASWException(RCode.GIT_COMMIT_CONFLICT_ERROR);
}
}
}
try (ObjectInserter inserter = repository.getObjectDatabase().newInserter();
TreeWalk treeWalk = new TreeWalk(repository);
RevWalk revWalk = new RevWalk(repository)) {
// branch tree
treeWalk.addTree(revWalk.parseTree(branchRef));
treeWalk.setRecursive(true);
DirCache newTree = DirCache.newInCore();
DirCacheBuilder newTreeBuilder = newTree.builder();
List<String> updateFilePath = updateContent.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<String, String> map : updateContent) {
String action = T.MapUtil.getStr(map, "action");
if (T.StrUtil.equalsAnyIgnoreCase(action, "create", "update")) {
String path = T.MapUtil.getStr(map, "path");
DirCacheEntry dirCacheEntry = new DirCacheEntry(path);
dirCacheEntry.setFileMode(FileMode.REGULAR_FILE);
String content = T.MapUtil.getStr(map, "content");
String encoding = T.MapUtil.getStr(map, "encoding");
if ("base64".equals(encoding)) {
// binary
byte[] data = Base64.getDecoder().decode(content);
ObjectId objectId = this.insertBlobFileToDatabase(repository, data);
dirCacheEntry.setObjectId(objectId);
} else {
// text
ObjectId objectId = this.insertBlobFileToDatabase(repository, content.getBytes());
dirCacheEntry.setObjectId(objectId);
}
newTreeBuilder.add(dirCacheEntry);
}
}
newTreeBuilder.finish();
ObjectId newTreeId = newTree.writeTree(inserter);
this.createCommit(repository, branch, newTreeId, message);
}
} catch (IOException | GitAPIException e) {
log.error(e, "[updateApplication] [error] [workspaceId: {}] [branch: {}] [lastCommitId: {}]", workspaceId, branch, lastCommitId);
throw new ASWException(RCode.ERROR);
}
}
@Override
public List<Map<Object, Object>> listApplicationCommit(String workspaceId, String branch, String applicationName, String file) {
List<Map<Object, Object>> resultList = T.ListUtil.list(true);
File repoDir = this.getRepoDirPath(workspaceId);
try (Git git = this.getGitInstance(repoDir)) {
String filterPath = T.StrUtil.concat(true, "applications/", applicationName);
if (T.StrUtil.isNotEmpty(file)) {
filterPath = T.StrUtil.concat(true, filterPath, "/", file);
}
ObjectId branchRef = git.getRepository().resolve(branch);
Iterable<RevCommit> iterable = git.log()
.add(branchRef)
.addPath(filterPath)
.call();
for (RevCommit commit : iterable) {
resultList.add(this.buildAswCommitInfo(commit));
}
} catch (IOException | GitAPIException e) {
log.error(e, "[listApplicationCommit] [error] [workspaceId: {}] [branch: {}] [application: {}]", workspaceId, branch, applicationName);
throw new ASWException(RCode.ERROR);
}
return resultList;
}
@Override
public Map<Object, Object> infoApplicationFileContent(String workspaceId, String branch, String applicationName, String commitId1111, String file) {
// applications/qq/basic.json
String path = T.StrUtil.concat(true, "applications/", applicationName, "/", file);
Map<Object, Object> result = T.MapUtil.builder()
.put("path", path)
.build();
File repoDir = this.getRepoDirPath(workspaceId);
try (Git git = getGitInstance(repoDir)) {
Repository repository = git.getRepository();
try (TreeWalk treeWalk = new TreeWalk(repository);
RevWalk revWalk = new RevWalk(repository);
) {
RevCommit revCommit = revWalk.parseCommit(ObjectId.fromString(commitId1111));
ObjectId treeId = revCommit.getTree().getId();
treeWalk.addTree(treeId);
treeWalk.setRecursive(true);
while (treeWalk.next()) {
if (T.StrUtil.equals(path, treeWalk.getPathString())) {
ObjectLoader loader = repository.open(treeWalk.getObjectId(0));
if (this.isBinary(treeWalk.getNameString())) {
String content = Base64.getEncoder().encodeToString(loader.getBytes());
result.put("encoding", "base64");
result.put("content", content);
} else {
result.put("encoding", "");
result.put("content", T.StrUtil.utf8Str(loader.getBytes()));
}
}
}
}
} catch (IOException e) {
log.error(e, "[infoApplicationFileContent] [error] [workspaceId: {}] [branch: {}] [application: {}]", workspaceId, branch, applicationName);
throw new ASWException(RCode.ERROR);
}
return result;
}
/**
* build asw commit info
*
* @param commit
* @return
*/
private Map<Object, Object> buildAswCommitInfo(RevCommit commit) {
if (null == commit) {
return T.MapUtil.newHashMap();
}
Map<Object, Object> m = new LinkedHashMap<>();
m.put("id", commit.getName());
m.put("shortId", T.StrUtil.subPre(commit.getName(), 8));
m.put("createdAt", TimeUnit.SECONDS.toMillis(commit.getCommitTime()));
m.put("title", commit.getShortMessage());
m.put("message", commit.getFullMessage());
List<String> parentIds = Arrays.stream(commit.getParents()).map(RevCommit::getName).collect(Collectors.toList());
m.put("parentIds", parentIds);
PersonIdent authorIdent = commit.getAuthorIdent();
m.put("authorName", authorIdent.getName());
m.put("authorEmail", authorIdent.getEmailAddress());
m.put("authoredDate", authorIdent.getWhen().getTime());
PersonIdent committerIdent = commit.getCommitterIdent();
m.put("committerName", committerIdent.getName());
m.put("committerEmail", committerIdent.getEmailAddress());
m.put("committedDate", committerIdent.getWhen().getTime());
return m;
}
/**
* 将 file object 添加到 objectDatabases,也就是 ./objects 目录下
*
* @param repository
* @param data
* @return
* @throws IOException
*/
private ObjectId insertBlobFileToDatabase(Repository repository, byte[] data) throws IOException {
try (ObjectInserter inserter = repository.getObjectDatabase().newInserter()) {
ObjectId blobId = inserter.insert(Constants.OBJ_BLOB, data);
inserter.flush();
return blobId;
}
}
/**
* commit
*
* @param repo
* @param branch
* @param treeId
* @param message
* @throws IOException
*/
public void createCommit(Repository repo, String branch, ObjectId treeId, String message) throws IOException {
try (ObjectInserter inserter = repo.getObjectDatabase().newInserter();
RevWalk revWalk = new RevWalk(repo);) {
CommitBuilder builder = new CommitBuilder();
builder.setTreeId(treeId);
builder.setMessage(message);
ObjectId branchRef = repo.resolve(branch);
if (null != branchRef) {
RevCommit parentId = revWalk.parseCommit(branchRef);
builder.setParentId(parentId);
}
SysUserEntity loginUserEntity = userService.getById(StpUtil.getLoginIdAsString());
builder.setAuthor(new PersonIdent(loginUserEntity.getName(), "asw@geedgenetworks.com"));
builder.setCommitter(new PersonIdent(loginUserEntity.getName(), "asw@geedgenetworks.com"));
// 插入新的提交对象
ObjectId commitId = inserter.insert(builder);
inserter.flush();
// 更新 branch 指向新的提交
if (null != branchRef) {
RefUpdate refUpdate = repo.updateRef(branch);
refUpdate.setNewObjectId(commitId);
refUpdate.update();
} else {
RefUpdate refUpdate = repo.updateRef(Constants.HEAD);
refUpdate.setNewObjectId(commitId);
refUpdate.update();
}
}
}
}

View File

@@ -139,5 +139,9 @@ INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (231, '302002', 'PLAYBOOK_NAME_DUPLICATE', '剧本名称重复', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (232, '601005', 'ENVIRONMENT_ID_CANNOT_EMPTY', 'environment id cannot be empty', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (233, '601005', 'ENVIRONMENT_ID_CANNOT_EMPTY', '环境 id 不能为空', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (234, '202003', 'PACKAGE_FILE_TYPE_ERROR', 'package invalid file', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (235, '202003', 'PACKAGE_FILE_TYPE_ERROR', '无效安装包文件', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (236, '203001', 'GIT_COMMIT_CONFLICT_ERROR', 'Commit failed; fix conflicts and then commit the result', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (237, '203001', 'GIT_COMMIT_CONFLICT_ERROR', '提交失败;解决冲突,然后提交结果', 'zh', '', 'admin', 1724030366000);
SET FOREIGN_KEY_CHECKS = 1;