feat: ASW-182 新增 tag,release 接口

This commit is contained in:
shizhendong
2024-11-21 14:59:54 +08:00
parent 70feac12fc
commit 3cc928d7a7
16 changed files with 733 additions and 11 deletions

View File

@@ -186,6 +186,13 @@
<version>7.0.0.202409031743-r</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit.archive -->
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.archive</artifactId>
<version>7.0.0.202409031743-r</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>

View File

@@ -146,7 +146,9 @@ public class Constants {
PLAYBOOK("playbook"),
JOB("job");
JOB("job"),
RELEASE("release");
private String type;

View File

@@ -67,6 +67,9 @@ public enum RCode {
GIT_BINARY_CONFLICT_ERROR(203004, "Binary file conflict found; resolve conflicts in binary files manually"),
GIT_MERGE_NOT_SUPPORTED(203005, "Cannot merge in the {0} state"),
GIT_MERGE_TARGET_BRANCH_NOT_EXIST(203006, "The target branch {0} does not exist."),
GIT_TAG_ALREADY_EXISTS(203007, "Tag {0} already exists"),
GIT_TAG_NOT_FOUND(203008, "Tag {0} not found"),
GIT_TAG_ALREADY_IN_USE(203009,"Tag is already in use. Choose another tag."),
// Runner

View File

@@ -0,0 +1,78 @@
package net.geedge.asw.module.app.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.servlet.http.HttpServletResponse;
import net.geedge.asw.common.util.*;
import net.geedge.asw.module.app.entity.ApplicationReleaseEntity;
import net.geedge.asw.module.app.service.IApplicationReleaseService;
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
import net.geedge.asw.module.workspace.service.IWorkspaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/workspace")
public class ApplicationReleaseController {
@Autowired
private IWorkspaceService workspaceService;
@Autowired
private IApplicationReleaseService releaseService;
@GetMapping("/{workspaceId}/release/{id}")
public R detail(@PathVariable("workspaceId") String workspaceId, @PathVariable("id") String id) {
ApplicationReleaseEntity record = releaseService.queryInfo(id);
return R.ok().putData("record", record);
}
@GetMapping("/{workspaceId}/release")
public R list(@PathVariable("workspaceId") String workspaceId, @RequestParam Map<String, Object> params) {
// workspaceId
params = T.MapUtil.defaultIfEmpty(params, new HashMap<>());
params.put("workspaceId", workspaceId);
Page page = releaseService.queryList(params);
return R.ok(page);
}
@PostMapping("/{workspaceId}/release")
public R add(@PathVariable("workspaceId") String workspaceId, @RequestBody Map<String, String> requestBody) {
String name = T.MapUtil.getStr(requestBody, "name", "");
String tagName = T.MapUtil.getStr(requestBody, "tagName", "");
String description = T.MapUtil.getStr(requestBody, "description", "");
if (T.StrUtil.hasEmpty(name, tagName)) {
throw new ASWException(RCode.PARAM_CANNOT_EMPTY);
}
ApplicationReleaseEntity record = releaseService.saveRelease(workspaceId, name, tagName, description);
return R.ok().putData("record", record);
}
@DeleteMapping("/{workspaceId}/release/{id}")
public R delete(@PathVariable("workspaceId") String workspaceId, @PathVariable("id") String id) {
releaseService.removeRelease(id);
return R.ok();
}
@GetMapping("/{workspaceId}/release/{id}/file")
public void download(@PathVariable("workspaceId") String workspaceId,
@PathVariable("id") String id,
HttpServletResponse response) throws IOException {
ApplicationReleaseEntity release = releaseService.getById(id);
T.VerifyUtil.is(release).notNull(RCode.SYS_RECORD_NOT_FOUND);
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
T.VerifyUtil.is(workspace).notNull(RCode.SYS_RECORD_NOT_FOUND);
String fileName = T.StrUtil.concat(true, workspace.getName(), "-", release.getTagName(), ".zip");
byte[] fileBytes = T.FileUtil.readBytes(T.FileUtil.file(release.getPath()));
ResponseUtil.downloadFile(response, MediaType.APPLICATION_OCTET_STREAM_VALUE, fileName, fileBytes);
}
}

View File

@@ -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.ITagService;
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 TagController {
@Autowired
private ITagService tagService;
@GetMapping("/{workspaceId}/tag/{tagName}")
public R infoTag(@PathVariable("workspaceId") String workspaceId, @PathVariable("tagName") String name) {
Map<Object, Object> record = tagService.infoTag(workspaceId, name);
return R.ok().putData("record", record);
}
@GetMapping("/{workspaceId}/tag")
public R listTag(@PathVariable("workspaceId") String workspaceId,
@RequestParam(value = "search", required = false) String search) {
List<Map<Object, Object>> list = tagService.listTag(workspaceId, search);
return R.ok().putData("records", list);
}
@PostMapping("/{workspaceId}/tag")
public synchronized R newTag(@PathVariable("workspaceId") String workspaceId, @RequestBody Map<String, String> requestBody) {
String name = T.MapUtil.getStr(requestBody, "name", "");
String ref = T.MapUtil.getStr(requestBody, "ref", "");
String description = T.MapUtil.getStr(requestBody, "description", "");
if (T.StrUtil.hasEmpty(name, ref)) {
throw new ASWException(RCode.PARAM_CANNOT_EMPTY);
}
Map<Object, Object> record = tagService.newTag(workspaceId, name, ref, description);
return R.ok().putData("record", record);
}
@DeleteMapping("/{workspaceId}/tag/{tagName}")
public synchronized R deleteTag(@PathVariable("workspaceId") String workspaceId, @PathVariable("tagName") String name) {
tagService.deleteTag(workspaceId, name);
return R.ok();
}
}

View File

@@ -0,0 +1,17 @@
package net.geedge.asw.module.app.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.geedge.asw.module.app.entity.ApplicationReleaseEntity;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
@Mapper
public interface ApplicationReleaseDao extends BaseMapper<ApplicationReleaseEntity> {
List<ApplicationReleaseEntity> queryList(Page page, Map<String, Object> params);
}

View File

@@ -0,0 +1,40 @@
package net.geedge.asw.module.app.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import net.geedge.asw.module.sys.entity.SysUserEntity;
@Data
@TableName(value = "application_release", autoResultMap = true)
public class ApplicationReleaseEntity {
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String name;
private String tagName;
private String path;
private String description;
private String createUserId;
private Long createTimestamp;
private String updateUserId;
private Long updateTimestamp;
private String workspaceId;
@TableField(exist = false)
private SysUserEntity createUser;
@TableField(exist = false)
private SysUserEntity updateUser;
@TableField(exist = false)
private Object commit;
}

View File

@@ -0,0 +1,21 @@
package net.geedge.asw.module.app.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import net.geedge.asw.module.app.entity.ApplicationReleaseEntity;
import java.util.Map;
public interface IApplicationReleaseService extends IService<ApplicationReleaseEntity> {
ApplicationReleaseEntity queryInfo(String id);
Page queryList(Map<String, Object> params);
ApplicationReleaseEntity saveRelease(String workspaceId, String name, String tagName, String description);
void removeRelease(String id);
void removeRelease(String workspaceId, String tagName);
}

View File

@@ -0,0 +1,16 @@
package net.geedge.asw.module.app.service;
import java.util.List;
import java.util.Map;
public interface ITagService {
Map<Object, Object> infoTag(String workspaceId, String name);
List<Map<Object, Object>> listTag(String workspaceId, String search);
Map<Object, Object> newTag(String workspaceId, String name, String branch, String message);
void deleteTag(String workspaceId, String name);
}

View File

@@ -0,0 +1,164 @@
package net.geedge.asw.module.app.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.geedge.asw.common.config.Query;
import net.geedge.asw.common.util.*;
import net.geedge.asw.module.app.dao.ApplicationReleaseDao;
import net.geedge.asw.module.app.entity.ApplicationReleaseEntity;
import net.geedge.asw.module.app.service.IApplicationReleaseService;
import net.geedge.asw.module.app.util.JGitUtils;
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.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@Service
public class ApplicationReleaseServiceImpl extends ServiceImpl<ApplicationReleaseDao, ApplicationReleaseEntity> implements IApplicationReleaseService {
private final static Log log = Log.get();
@Value("${asw.resources.path:resources}")
private String aswResourcesPath;
@Autowired
private ISysUserService userService;
@Autowired
private IWorkspaceService workspaceService;
@Override
public ApplicationReleaseEntity queryInfo(String id) {
ApplicationReleaseEntity entity = this.getById(id);
T.VerifyUtil.is(entity).notNull(RCode.SYS_RECORD_NOT_FOUND);
SysUserEntity createUser = userService.getById(entity.getCreateUserId());
SysUserEntity updateUser = userService.getById(entity.getUpdateUserId());
createUser.setPwd(null);
updateUser.setPwd(null);
entity.setCreateUser(createUser);
entity.setUpdateUser(updateUser);
File gitDir = workspaceService.getGitDir(entity.getWorkspaceId());
try (Repository repository = JGitUtils.openRepository(gitDir);) {
Ref tagRef = repository.findRef(JGitUtils.getFullTagName(entity.getTagName()));
String tgtCommitId = tagRef.getTarget().getObjectId().getName();
RevCommit revCommit = JGitUtils.infoCommit(repository, tgtCommitId);
entity.setCommit(JGitUtils.buildAswCommitInfo(revCommit));
return entity;
} catch (IOException e) {
log.error(e, "[queryInfo] [id: {}]", id);
throw new RuntimeException(e);
}
}
@Override
public Page queryList(Map<String, Object> params) {
Page page = new Query(ApplicationReleaseEntity.class).getPage(params);
List<ApplicationReleaseEntity> entityList = this.getBaseMapper().queryList(page, params);
page.setRecords(entityList);
return page;
}
@Override
public ApplicationReleaseEntity saveRelease(String workspaceId, String name, String tagName, String description) {
ApplicationReleaseEntity checkTagInUse = this.getOne(new LambdaQueryWrapper<ApplicationReleaseEntity>()
.eq(ApplicationReleaseEntity::getWorkspaceId, workspaceId)
.eq(ApplicationReleaseEntity::getTagName, tagName)
);
if (null != checkTagInUse) {
throw new ASWException(RCode.GIT_TAG_ALREADY_IN_USE);
}
String uuid = T.StrUtil.uuid();
// release file
File releaseFile = FileResourceUtil.createFile(this.aswResourcesPath, workspaceId, Constants.FileTypeEnum.RELEASE.getType(), uuid, uuid + ".zip");
File gitDir = workspaceService.getGitDir(workspaceId);
try (Repository repository = JGitUtils.openRepository(gitDir);) {
Ref tagRef = repository.findRef(JGitUtils.getFullTagName(tagName));
T.VerifyUtil.is(tagRef).notNull(RCode.GIT_TAG_NOT_FOUND.setParam(tagName));
// archive
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
String prefix = T.StrUtil.concat(true, workspace.getName(), "-", tagName, "/");
JGitUtils.archive(repository, tagName, releaseFile, prefix, "zip");
ApplicationReleaseEntity entity = new ApplicationReleaseEntity();
entity.setId(uuid);
entity.setName(name);
entity.setTagName(tagName);
entity.setPath(releaseFile.getAbsolutePath());
entity.setDescription(description);
entity.setWorkspaceId(workspaceId);
entity.setCreateUserId(StpUtil.getLoginIdAsString());
entity.setCreateTimestamp(System.currentTimeMillis());
entity.setUpdateUserId(StpUtil.getLoginIdAsString());
entity.setUpdateTimestamp(System.currentTimeMillis());
this.save(entity);
// build record info
SysUserEntity createUser = userService.getById(entity.getCreateUserId());
SysUserEntity updateUser = userService.getById(entity.getUpdateUserId());
createUser.setPwd(null);
updateUser.setPwd(null);
entity.setCreateUser(createUser);
entity.setUpdateUser(updateUser);
String tgtCommitId = tagRef.getTarget().getObjectId().getName();
RevCommit revCommit = JGitUtils.infoCommit(repository, tgtCommitId);
entity.setCommit(JGitUtils.buildAswCommitInfo(revCommit));
return entity;
} catch (IOException | GitAPIException e) {
T.FileUtil.del(releaseFile);
log.error(e, "[saveRelease] [error] [workspaceId: {}] [name: {}] [tagName: {}]", workspaceId, name, tagName);
throw new RuntimeException(e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void removeRelease(String id) {
ApplicationReleaseEntity entity = this.getById(id);
if (null != entity) {
// del file
T.FileUtil.del(entity.getPath());
// del record
this.removeById(id);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void removeRelease(String workspaceId, String tagName) {
ApplicationReleaseEntity entity = this.getOne(new LambdaQueryWrapper<ApplicationReleaseEntity>()
.eq(ApplicationReleaseEntity::getWorkspaceId, workspaceId)
.eq(ApplicationReleaseEntity::getTagName, tagName)
);
if (null != entity) {
// del file
T.FileUtil.del(entity.getPath());
// del record
this.removeById(entity.getId());
}
}
}

View File

@@ -46,8 +46,8 @@ public class BranchServiceImpl implements IBranchService {
String fullBranch = repository.getFullBranch();
String defaultBranch = "main";
if (fullBranch != null && fullBranch.startsWith(JGitUtils.LOCAL_BRANCH_PREFIX)) {
defaultBranch = fullBranch.substring(JGitUtils.LOCAL_BRANCH_PREFIX.length());
if (fullBranch != null && fullBranch.startsWith(JGitUtils.R_HEADS)) {
defaultBranch = fullBranch.substring(JGitUtils.R_HEADS.length());
}
// 默认行为,进查询本地分支
@@ -57,7 +57,7 @@ public class BranchServiceImpl implements IBranchService {
for (Ref ref : call) {
String branchName = ref.getName();
// 返回时去掉前缀
branchName = branchName.replaceAll(JGitUtils.LOCAL_BRANCH_PREFIX, "");
branchName = branchName.replaceAll(JGitUtils.R_HEADS, "");
if (T.StrUtil.isNotEmpty(search)) {
if (!T.StrUtil.contains(branchName, search)) {
continue;

View File

@@ -0,0 +1,194 @@
package net.geedge.asw.module.app.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.entity.ApplicationReleaseEntity;
import net.geedge.asw.module.app.service.IApplicationReleaseService;
import net.geedge.asw.module.app.service.ITagService;
import net.geedge.asw.module.app.util.JGitUtils;
import net.geedge.asw.module.sys.entity.SysUserEntity;
import net.geedge.asw.module.sys.service.ISysUserService;
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.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class TagServiceImpl implements ITagService {
private final static Log log = Log.get();
@Autowired
private ISysUserService userService;
@Autowired
private IWorkspaceService workspaceService;
@Autowired
private IApplicationReleaseService releaseService;
private String getShortTagName(String name) {
return name.startsWith(JGitUtils.R_TAGS) ? name.replaceAll(JGitUtils.R_TAGS, "") : name;
}
@Override
public Map<Object, Object> infoTag(String workspaceId, String name) {
File gitDir = workspaceService.getGitDir(workspaceId);
try (Repository repository = JGitUtils.openRepository(gitDir);) {
Map<Object, Object> infoTag = this.infoTag(repository, name);
return infoTag;
} catch (IOException e) {
log.error(e, "[infoTag] [error] [workspaceId: {}] [name: {}]", workspaceId, name);
throw new RuntimeException(e);
}
}
/**
* tag 详情
*
* @param repository
* @param name
* @return
* @throws IOException
*/
private Map<Object, Object> infoTag(Repository repository, String name) throws IOException {
Ref ref = repository.findRef(JGitUtils.getFullTagName(name));
T.VerifyUtil.is(ref).notNull(RCode.GIT_TAG_NOT_FOUND.setParam(name));
// tag
RevTag revTag = JGitUtils.infoTag(repository, ref.getObjectId());
String message = revTag.getFullMessage();
// commit
RevCommit revCommit = JGitUtils.infoCommit(repository, ref.getObjectId().getName());
Map<Object, Object> aswCommitInfo = JGitUtils.buildAswCommitInfo(revCommit);
// release
ApplicationReleaseEntity releaseEntity = releaseService.getOne(new LambdaQueryWrapper<ApplicationReleaseEntity>()
.eq(ApplicationReleaseEntity::getWorkspaceId, repository.getDirectory().getName())
.eq(ApplicationReleaseEntity::getTagName, this.getShortTagName(name))
);
Map<Object, Object> m = T.MapUtil.builder()
.put("name", this.getShortTagName(name))
.put("message", message)
.put("createdAt", revTag.getTaggerIdent().getWhen().getTime())
.put("commit", aswCommitInfo)
.put("release", releaseEntity)
.build();
return m;
}
@Override
public List<Map<Object, Object>> listTag(String workspaceId, String search) {
File gitDir = workspaceService.getGitDir(workspaceId);
try (Repository repository = JGitUtils.openRepository(gitDir);
Git git = Git.open(repository.getDirectory())) {
List<Ref> refList = git.tagList().call();
if (T.StrUtil.isNotEmpty(search)) {
refList = refList.stream()
.filter(ref -> {
String name = ref.getName();
return T.StrUtil.containsIgnoreCase(this.getShortTagName(name), search);
})
.collect(Collectors.toList());
}
List<Map<Object, Object>> list = T.ListUtil.list(true);
for (Ref ref : refList) {
list.add(this.infoTag(repository, ref.getName()));
}
// 默认根据 createdAt 字段排序
list = list.stream()
.sorted(Comparator.comparing(map -> T.MapUtil.getLong((Map) map, "createdAt")).reversed())
.collect(Collectors.toList());
return list;
} catch (IOException | GitAPIException e) {
log.error(e, "[listTag] [error] [workspaceId: {}] [search: {}]", workspaceId, search);
throw new RuntimeException(e);
}
}
@Override
public Map<Object, Object> newTag(String workspaceId, String name, String branch, String message) {
File gitDir = workspaceService.getGitDir(workspaceId);
try (Repository repository = JGitUtils.openRepository(gitDir);
Git git = Git.open(repository.getDirectory())) {
// check tag exists
List<Ref> tagListInDb = git.tagList().call();
Ref checkRefExists = tagListInDb.parallelStream()
.filter(ref -> T.StrUtil.equals(name, this.getShortTagName(ref.getName())))
.findFirst()
.orElse(null);
if (null != checkRefExists) {
throw new ASWException(RCode.GIT_TAG_ALREADY_EXISTS.setParam(name));
}
// check branch exists
if (T.BooleanUtil.negate(
JGitUtils.isBranchExists(repository, branch)
)) {
throw new ASWException(RCode.GIT_MERGE_TARGET_BRANCH_NOT_EXIST.setParam(branch));
}
SysUserEntity loginUser = userService.getById(StpUtil.getLoginIdAsString());
PersonIdent personIdent = JGitUtils.buildPersonIdent(loginUser.getName());
RevCommit branchLatestCommit = JGitUtils.getBranchLatestCommit(repository, branch);
// add tag
git.tag()
.setName(name)
.setMessage(message)
.setTagger(personIdent)
.setObjectId(branchLatestCommit)
.setAnnotated(true)
.setForceUpdate(false)
.call();
// return info
return this.infoTag(repository, name);
} catch (IOException | GitAPIException e) {
log.error(e, "[newTag] [error] [workspaceId: {}] [name: {}] [branch: {}]", workspaceId, name, branch);
throw new RuntimeException(e);
}
}
@Override
public void deleteTag(String workspaceId, String name) {
File gitDir = workspaceService.getGitDir(workspaceId);
try (Repository repository = JGitUtils.openRepository(gitDir);
Git git = Git.open(repository.getDirectory())) {
// del tag
git.tagDelete()
.setTags(name)
.call();
// del release
releaseService.removeRelease(workspaceId, name);
} catch (IOException | GitAPIException e) {
log.error(e, "[deleteTag] [error] [workspaceId: {}] [name: {}]", workspaceId, name);
throw new RuntimeException(e);
}
}
}

View File

@@ -9,6 +9,7 @@ import org.eclipse.jgit.api.*;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.archive.ArchiveFormats;
import org.eclipse.jgit.diff.*;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
@@ -20,6 +21,7 @@ import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.RecursiveMerger;
import org.eclipse.jgit.merge.ThreeWayMerger;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
@@ -30,9 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -49,7 +49,9 @@ public class JGitUtils {
/**
* 本地分支引用前缀
*/
public static final String LOCAL_BRANCH_PREFIX = "refs/heads/";
public static final String R_HEADS = "refs/heads/";
public static final String R_TAGS = "refs/tags/";
/**
* 默认分支
@@ -123,7 +125,7 @@ public class JGitUtils {
* @throws IOException
*/
public static boolean isBranchExists(Repository repository, String branch) throws IOException {
Ref ref = repository.findRef(T.StrUtil.concat(true, LOCAL_BRANCH_PREFIX, branch));
Ref ref = repository.findRef(T.StrUtil.concat(true, R_HEADS, branch));
return null != ref;
}
@@ -142,6 +144,24 @@ public class JGitUtils {
}
}
public static String getFullTagName(String name) {
return name.startsWith(R_TAGS) ? name : T.StrUtil.concat(true, R_TAGS, name);
}
/**
* 获取tag对象
*
* @param repository
* @param objectId
* @return
* @throws IOException
*/
public static RevTag infoTag(Repository repository, ObjectId objectId) throws IOException {
try (RevWalk revWalk = new RevWalk(repository)) {
RevTag revTag = revWalk.parseTag(objectId);
return revTag;
}
}
/**
* 返回分支最新提交
@@ -357,7 +377,7 @@ public class JGitUtils {
RefUpdate ru = null;
RefUpdate.Result rc = null;
if (null != branchRef) {
ru = repository.updateRef(T.StrUtil.concat(true, LOCAL_BRANCH_PREFIX, branch));
ru = repository.updateRef(T.StrUtil.concat(true, R_HEADS, branch));
ru.setNewObjectId(commitId);
rc = ru.update();
} else {
@@ -422,7 +442,7 @@ public class JGitUtils {
ObjectId commitId = odi.insert(commit);
odi.flush();
RefUpdate ru = repository.updateRef(T.StrUtil.concat(true, JGitUtils.LOCAL_BRANCH_PREFIX, branch));
RefUpdate ru = repository.updateRef(T.StrUtil.concat(true, R_HEADS, branch));
ru.setNewObjectId(commitId);
RefUpdate.Result rc = ru.update();
switch (rc) {
@@ -744,6 +764,34 @@ public class JGitUtils {
}
}
/**
* 归档
*
* @param repository
* @param tagName
* @param file
* @param prefix
* @param format
* @throws IOException
* @throws GitAPIException
*/
public static void archive(Repository repository, String tagName, File file, String prefix, String format) throws IOException, GitAPIException {
ArchiveFormats.registerAll();
T.FileUtil.mkdir(T.FileUtil.getParent(file, 1));
try (OutputStream out = new FileOutputStream(file)) {
try (Git git = new Git(repository)) {
git.archive()
.setTree(repository.resolve(tagName))
.setFormat(format)
.setPrefix(prefix)
.setOutputStream(out)
.call();
}
} finally {
ArchiveFormats.unregisterAll();
}
}
/**
* build asw commit info
*

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="net.geedge.asw.module.app.dao.ApplicationReleaseDao">
<!-- 通用查询映射结果 -->
<resultMap id="resultMap" type="net.geedge.asw.module.app.entity.ApplicationReleaseEntity">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="tag_name" property="tagName"/>
<result column="path" property="path"/>
<result column="description" property="description"/>
<result column="create_timestamp" property="createTimestamp"/>
<result column="create_user_id" property="createUserId"/>
<result column="update_timestamp" property="updateTimestamp"/>
<result column="update_user_id" property="updateUserId"/>
<result column="workspace_id" property="workspaceId"/>
<association property="createUser" columnPrefix="c_" javaType="net.geedge.asw.module.sys.entity.SysUserEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="userName" column="user_name"/>
</association>
<association property="updateUser" columnPrefix="u_" javaType="net.geedge.asw.module.sys.entity.SysUserEntity">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="userName" column="user_name"/>
</association>
</resultMap>
<select id="queryList" resultMap="resultMap">
SELECT
ar.*,
c.id AS c_id,
c.name AS c_name,
c.user_name AS c_user_name,
u.id AS u_id,
u.name AS u_name,
u.user_name AS u_user_name
FROM
application_release ar
LEFT JOIN sys_user c ON ar.create_user_id = c.id
LEFT JOIN sys_user u ON ar.update_user_id = u.id
<where>
<if test="params.workbookId != null and params.workbookId != ''">
ar.workbook_id = #{params.workbookId}
</if>
<if test="params.q != null and params.q != ''">
AND ( locate(#{params.q}, ar.name) OR locate(#{params.q}, ar.tag_name) OR locate(#{params.q}, ar.description) )
</if>
</where>
</select>
</mapper>

View File

@@ -157,5 +157,11 @@ 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 (249, '203005', 'GIT_MERGE_NOT_SUPPORTED', '无法在{0}状态下合并', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (250, '203006', 'GIT_MERGE_TARGET_BRANCH_NOT_EXIST', 'The target branch {0} does not exist.', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (251, '203006', 'GIT_MERGE_TARGET_BRANCH_NOT_EXIST', '目标分支 {0} 不存在', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (253, '203007', 'GIT_TAG_ALREADY_EXISTS', 'Tag {0} already exists', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (255, '203007', 'GIT_TAG_ALREADY_EXISTS', 'Tag {0} 已经存在', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (257, '203008', 'GIT_TAG_NOT_FOUND', 'Tag {0} not found', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (259, '203008', 'GIT_TAG_NOT_FOUND', 'Tag {0} 不存在', 'zh', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (261, '203009', 'GIT_TAG_ALREADY_IN_USE', 'Tag is already in use. Choose another tag.', 'en', '', 'admin', 1724030366000);
INSERT INTO `sys_i18n`(`id`, `name`, `code`, `value`, `lang`, `remark`, `update_user_id`, `update_timestamp`) VALUES (263, '203009', 'GIT_TAG_ALREADY_IN_USE', 'Tag 已在使用中,请选择其他 tag', 'zh', '', 'admin', 1724030366000);
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -375,6 +375,25 @@ CREATE TABLE `application_merge` (
KEY `idx_workspace_id` (`workspace_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/**
* 新增 application_release 表
*/
DROP TABLE IF EXISTS `application_release`;
CREATE TABLE `application_release` (
`id` VARCHAR(64) NOT NULL COMMENT '主键',
`tag_name` VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'git tag名称',
`name` VARCHAR(256) NOT NULL DEFAULT '' COMMENT '标题',
`description` text NOT NULL DEFAULT '' COMMENT '描述信息',
`path` VARCHAR(1024) NOT NULL DEFAULT '' COMMENT '打包文件路径',
`create_timestamp` bigint(20) NOT NULL COMMENT '创建时间戳',
`create_user_id` varchar(64) NOT NULL COMMENT '创建人',
`update_timestamp` bigint(20) NOT NULL COMMENT '更新时间戳',
`update_user_id` varchar(64) NOT NULL COMMENT '更新人',
`workspace_id` varchar(64) NOT NULL DEFAULT '' COMMENT '工作空间ID',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_workspace_id` (`workspace_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
/**
* 新增 package 表
*/