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
|
||||
save-path: D:\Upload\
|
||||
|
||||
# 部署配置
|
||||
deploy:
|
||||
secret: cRc5888KAo4TxRS4y5iv35GM
|
||||
app-dir: /home/dtyx/znpt-backend
|
||||
|
|
Loading…
Reference in New Issue