gitee-webhook 测试
This commit is contained in:
parent
52d2a2f486
commit
5f77193e57
|
@ -0,0 +1,157 @@
|
||||||
|
package com.dite.znpt.web.controller;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Hex;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class DeployController {
|
||||||
|
|
||||||
|
@Value("${deploy.secret}")
|
||||||
|
private String secret;
|
||||||
|
|
||||||
|
@Value("${deploy.app-dir}")
|
||||||
|
private String appDir;
|
||||||
|
|
||||||
|
private Process deploymentProcess;
|
||||||
|
|
||||||
|
@PostMapping("/gitee-webhook")
|
||||||
|
public ResponseEntity<String> handleWebhook(
|
||||||
|
@RequestHeader(value = "X-Gitee-Token", required = false) String signature,
|
||||||
|
@RequestBody String payload) {
|
||||||
|
|
||||||
|
// 验证签名
|
||||||
|
if (signature == null || !signature.equals(calculateSignature(payload))) {
|
||||||
|
return ResponseEntity.status(401).body("无效签名");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安全启动部署
|
||||||
|
startDeployment();
|
||||||
|
|
||||||
|
return ResponseEntity.ok("部署流程已启动");
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/deployment-status")
|
||||||
|
public ResponseEntity<String> getDeploymentStatus() {
|
||||||
|
try {
|
||||||
|
Path statusFile = Path.of(appDir, "deployment-status.txt");
|
||||||
|
if (!Files.exists(statusFile)) {
|
||||||
|
return ResponseEntity.ok("尚未开始部署");
|
||||||
|
}
|
||||||
|
|
||||||
|
String statusContent = Files.readString(statusFile);
|
||||||
|
return ResponseEntity.ok(statusContent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(500).body("状态读取错误: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/deployment-log")
|
||||||
|
public ResponseEntity<String> getDeploymentLog(
|
||||||
|
@RequestParam(defaultValue = "20") int lines) {
|
||||||
|
try {
|
||||||
|
Path logFile = Path.of(appDir, "deploy.log");
|
||||||
|
if (!Files.exists(logFile)) {
|
||||||
|
return ResponseEntity.ok("无可用日志");
|
||||||
|
}
|
||||||
|
|
||||||
|
String logContent;
|
||||||
|
if (lines > 0) {
|
||||||
|
logContent = tail(logFile, lines);
|
||||||
|
} else {
|
||||||
|
logContent = Files.readString(logFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok("<pre>" + logContent + "</pre>");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(500).body("日志读取错误: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void startDeployment() {
|
||||||
|
// 防止重复部署
|
||||||
|
if (deploymentProcess != null && deploymentProcess.isAlive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 清理旧状态
|
||||||
|
Files.deleteIfExists(Path.of(appDir, "deployment-status.txt"));
|
||||||
|
|
||||||
|
// 启动部署脚本
|
||||||
|
ProcessBuilder builder = new ProcessBuilder("./deploy.sh");
|
||||||
|
builder.directory(new File(appDir));
|
||||||
|
builder.redirectErrorStream(true);
|
||||||
|
|
||||||
|
deploymentProcess = builder.start();
|
||||||
|
|
||||||
|
// 启动日志监控线程
|
||||||
|
new Thread(() -> {
|
||||||
|
try (BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(deploymentProcess.getInputStream()))) {
|
||||||
|
|
||||||
|
while (deploymentProcess.isAlive()) {
|
||||||
|
String line = reader.readLine();
|
||||||
|
if (line != null) {
|
||||||
|
System.out.println("[DEPLOY] " + line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int exitCode = deploymentProcess.waitFor();
|
||||||
|
System.out.println("部署进程结束,状态码: " + exitCode);
|
||||||
|
deploymentProcess = null;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("部署日志读取错误: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("启动部署脚本失败: " + e.getMessage());
|
||||||
|
try {
|
||||||
|
Files.writeString(Path.of(appDir, "deployment-status.txt"),
|
||||||
|
"START_FAILED - " + e.getMessage());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String tail(Path path, int lines) throws IOException {
|
||||||
|
ProcessBuilder builder = new ProcessBuilder("tail", "-n", String.valueOf(lines), path.toString());
|
||||||
|
Process process = builder.start();
|
||||||
|
|
||||||
|
StringBuilder output = new StringBuilder();
|
||||||
|
try (BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(process.getInputStream()))) {
|
||||||
|
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
output.append(line).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String calculateSignature(String payload) {
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||||
|
byte[] signatureBytes = digest.digest(
|
||||||
|
(payload + secret).getBytes(StandardCharsets.UTF_8)
|
||||||
|
);
|
||||||
|
return Hex.encodeHexString(signatureBytes);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("签名生成失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -137,3 +137,7 @@ upload:
|
||||||
# 此处仅定义总的父路径,细节定义到 FilePathEnum
|
# 此处仅定义总的父路径,细节定义到 FilePathEnum
|
||||||
save-path: D:\Upload\
|
save-path: D:\Upload\
|
||||||
|
|
||||||
|
# 部署配置
|
||||||
|
deploy:
|
||||||
|
secret: cRc5888KAo4TxRS4y5iv35GM
|
||||||
|
app-dir: /home/dtyx/znpt-backend
|
||||||
|
|
Loading…
Reference in New Issue