feat: ASW-182 新增 tag,release 接口
This commit is contained in:
7
pom.xml
7
pom.xml
@@ -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>
|
||||
|
||||
@@ -146,7 +146,9 @@ public class Constants {
|
||||
|
||||
PLAYBOOK("playbook"),
|
||||
|
||||
JOB("job");
|
||||
JOB("job"),
|
||||
|
||||
RELEASE("release");
|
||||
|
||||
private String type;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
|
||||
@@ -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 表
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user