Commit cd502bcf authored by chicheng's avatar chicheng

添加项目版本信息

parent 3741d13b
......@@ -15,6 +15,11 @@
web服务入口
</description>
<!-- Git 仓库在 mes 工程根目录(admin 的上一级),不在 admin 子模块内 -->
<properties>
<git.repository.path>${project.basedir}/..</git.repository.path>
</properties>
<dependencies>
<!-- spring-boot-devtools -->
......@@ -136,6 +141,32 @@
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
<!-- 打包写入 git.properties 并打入 admin.jar(须在 prepare-package,且构建机需有 mes/.git) -->
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.9.10</version>
<executions>
<execution>
<id>write-git-properties</id>
<goals>
<goal>revision</goal>
</goals>
<!-- 必须在打 jar 前写入 target/classes,initialize 阶段太早会导致 jar 内没有该文件 -->
<phase>prepare-package</phase>
</execution>
</executions>
<configuration>
<dotGitDirectory>${git.repository.path}</dotGitDirectory>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<!-- 与 huigou-cloud 一致:outputDirectory 已是 target/classes,勿再拼 /classes -->
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
<commitIdGenerationMode>full</commitIdGenerationMode>
<failOnNoGitDirectory>false</failOnNoGitDirectory>
<failOnUnableToExtractRepoInfo>false</failOnUnableToExtractRepoInfo>
<verbose>true</verbose>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
......
package com.ximai.web.controller.api;
import com.ximai.common.core.controller.BaseController;
import com.ximai.common.core.domain.AjaxResult;
import com.ximai.web.service.BuildVersionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 开放接口:查询当前部署包的 Git 构建版本(无需登录,见 SecurityConfig /api/**)
*/
@Api("开放接口-构建版本")
@RestController
@RequestMapping("/api/build")
public class OpenBuildVersionController extends BaseController {
@Autowired
private BuildVersionService buildVersionService;
@ApiOperation("查询 Git 打包版本信息")
@GetMapping("/version")
public AjaxResult getVersion() {
return AjaxResult.success(buildVersionService.getGitBuildVersion());
}
}
package com.ximai.web.service;
import com.ximai.common.config.RuoYiConfig;
import com.ximai.common.core.domain.vo.GitBuildVersionVo;
import com.ximai.common.utils.data.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/**
* 读取 Git 构建版本:优先 jar 内 git.properties(Maven prepare-package 生成),其次环境变量(CI),最后本机 git 命令。
*/
@Service
public class BuildVersionService {
private static final Logger log = LoggerFactory.getLogger(BuildVersionService.class);
private static final String GIT_PROPERTIES = "git.properties";
private static final DateTimeFormatter BUILD_TIME_FMT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX").withZone(ZoneId.systemDefault());
@Autowired
private RuoYiConfig ruoYiConfig;
public GitBuildVersionVo getGitBuildVersion() {
Properties git = loadGitProperties();
if (!hasGitInfo(git)) {
fillFromEnvironment(git);
}
if (!hasGitInfo(git)) {
fillFromGitCommand(git);
}
if (!hasGitInfo(git)) {
log.warn("未获取到 Git 版本:请确认 admin.jar 内含有 git.properties(在含 .git 的 mes 目录执行 mvn clean package -pl admin -am)");
}
GitBuildVersionVo vo = new GitBuildVersionVo();
vo.setApplication(ruoYiConfig.getName());
vo.setProjectVersion(ruoYiConfig.getVersion());
vo.setBranch(prop(git, "git.branch"));
vo.setCommitId(prop(git, "git.commit.id.abbrev"));
vo.setCommitIdFull(prop(git, "git.commit.id"));
vo.setCommitMessage(prop(git, "git.commit.message.short"));
vo.setCommitTime(prop(git, "git.commit.time"));
vo.setBuildTime(prop(git, "git.build.time"));
vo.setBuildVersion(prop(git, "git.build.version"));
vo.setTags(prop(git, "git.tags"));
return vo;
}
/**
* 从 classpath 读取(Spring Boot fat jar 为 BOOT-INF/classes/git.properties)
*/
private Properties loadGitProperties() {
Properties properties = new Properties();
InputStream in = null;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl != null) {
in = cl.getResourceAsStream(GIT_PROPERTIES);
}
if (in == null) {
in = BuildVersionService.class.getClassLoader().getResourceAsStream(GIT_PROPERTIES);
}
if (in == null) {
log.debug("classpath 中未找到 {}", GIT_PROPERTIES);
return properties;
}
try (InputStream stream = in) {
properties.load(stream);
log.debug("已加载 git.properties,keys={}", properties.size());
} catch (Exception e) {
log.warn("读取 git.properties 失败: {}", e.getMessage());
}
return properties;
}
private static boolean hasGitInfo(Properties git) {
if (git == null || git.isEmpty()) {
return false;
}
String id = git.getProperty("git.commit.id");
String abbrev = git.getProperty("git.commit.id.abbrev");
return (StringUtils.isNotEmpty(id) && !"unknown".equalsIgnoreCase(id))
|| (StringUtils.isNotEmpty(abbrev) && !"unknown".equalsIgnoreCase(abbrev));
}
/** Jenkins/GitLab 等 CI 可在打包时注入环境变量 */
private void fillFromEnvironment(Properties git) {
putEnv(git, "git.branch", "GIT_BRANCH", "CI_COMMIT_REF_NAME", "BRANCH_NAME");
putEnv(git, "git.commit.id", "GIT_COMMIT_ID", "CI_COMMIT_SHA", "GIT_COMMIT");
putEnv(git, "git.commit.id.abbrev", "GIT_COMMIT_ID_ABBREV", "CI_COMMIT_SHORT_SHA");
putEnv(git, "git.commit.message.short", "GIT_COMMIT_MESSAGE", "CI_COMMIT_MESSAGE");
putEnv(git, "git.commit.time", "GIT_COMMIT_TIME");
putEnv(git, "git.build.time", "BUILD_TIME", "CI_BUILD_TIME");
putEnv(git, "git.build.version", "BUILD_VERSION");
putEnv(git, "git.tags", "GIT_TAGS");
if (!git.containsKey("git.build.time")) {
git.setProperty("git.build.time", BUILD_TIME_FMT.format(Instant.now()));
}
if (!git.containsKey("git.build.version") && StringUtils.isNotEmpty(ruoYiConfig.getVersion())) {
git.setProperty("git.build.version", ruoYiConfig.getVersion());
}
if (StringUtils.isNotEmpty(git.getProperty("git.commit.id"))
&& !git.containsKey("git.commit.id.abbrev")) {
String full = git.getProperty("git.commit.id");
git.setProperty("git.commit.id.abbrev",
full.length() > 7 ? full.substring(0, 7) : full);
}
}
private static void putEnv(Properties git, String propKey, String... envKeys) {
if (StringUtils.isNotEmpty(git.getProperty(propKey))) {
return;
}
for (String envKey : envKeys) {
String val = System.getenv(envKey);
if (StringUtils.isNotEmpty(val)) {
git.setProperty(propKey, val.trim());
return;
}
}
}
private void fillFromGitCommand(Properties git) {
File gitRoot = resolveMesGitRoot();
if (gitRoot == null) {
return;
}
String branch = gitExec(gitRoot, "rev-parse", "--abbrev-ref", "HEAD");
String commitFull = gitExec(gitRoot, "rev-parse", "HEAD");
String commitShort = gitExec(gitRoot, "rev-parse", "--short", "HEAD");
String commitTime = gitExec(gitRoot, "log", "-1", "--format=%ci");
String commitMessage = gitExec(gitRoot, "log", "-1", "--format=%s");
String tags = gitExec(gitRoot, "describe", "--tags", "--always");
if (StringUtils.isNotEmpty(branch)) {
git.setProperty("git.branch", branch);
}
if (StringUtils.isNotEmpty(commitFull)) {
git.setProperty("git.commit.id", commitFull);
}
if (StringUtils.isNotEmpty(commitShort)) {
git.setProperty("git.commit.id.abbrev", commitShort);
}
if (StringUtils.isNotEmpty(commitTime)) {
git.setProperty("git.commit.time", commitTime);
}
if (StringUtils.isNotEmpty(commitMessage)) {
git.setProperty("git.commit.message.short", commitMessage);
}
if (StringUtils.isNotEmpty(tags) && !tags.contains("fatal")) {
git.setProperty("git.tags", tags);
}
git.setProperty("git.build.time", BUILD_TIME_FMT.format(Instant.now()));
if (StringUtils.isNotEmpty(ruoYiConfig.getVersion())) {
git.setProperty("git.build.version", ruoYiConfig.getVersion());
}
}
private static File resolveMesGitRoot() {
File start = new File(System.getProperty("user.dir")).getAbsoluteFile();
File dir = start;
while (dir != null) {
if (new File(dir, ".git").exists()) {
return dir;
}
dir = dir.getParentFile();
}
File parent = start.getParentFile();
if (parent != null && new File(parent, ".git").exists()) {
return parent;
}
return null;
}
private static String gitExec(File gitRoot, String... command) {
try {
String[] cmd = new String[command.length + 1];
cmd[0] = "git";
System.arraycopy(command, 0, cmd, 1, command.length);
Process process = new ProcessBuilder(cmd)
.directory(gitRoot)
.redirectErrorStream(true)
.start();
boolean finished = process.waitFor(3, TimeUnit.SECONDS);
if (!finished || process.exitValue() != 0) {
return null;
}
ByteArrayOutputStream buf = new ByteArrayOutputStream();
byte[] chunk = new byte[256];
int n;
InputStream in = process.getInputStream();
while ((n = in.read(chunk)) != -1) {
buf.write(chunk, 0, n);
}
String out = new String(buf.toByteArray(), StandardCharsets.UTF_8).trim();
return StringUtils.isEmpty(out) ? null : out;
} catch (Exception e) {
log.debug("git {} 执行失败: {}", String.join(" ", command), e.getMessage());
return null;
}
}
private static String prop(Properties properties, String key) {
String value = properties.getProperty(key);
return StringUtils.isNotEmpty(value) ? value.trim() : "unknown";
}
}
package com.ximai.common.core.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* Git 打包构建版本信息(开放接口返回)
*/
@Data
@ApiModel("Git打包版本信息")
public class GitBuildVersionVo {
@ApiModelProperty("应用名称")
private String application;
@ApiModelProperty("项目配置版本号")
private String projectVersion;
@ApiModelProperty("Git分支")
private String branch;
@ApiModelProperty("Git提交短ID")
private String commitId;
@ApiModelProperty("Git提交完整ID")
private String commitIdFull;
@ApiModelProperty("Git提交说明")
private String commitMessage;
@ApiModelProperty("Git提交时间")
private String commitTime;
@ApiModelProperty("构建时间")
private String buildTime;
@ApiModelProperty("构建版本(git.build.version)")
private String buildVersion;
@ApiModelProperty("Git标签")
private String tags;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment