前言 🔗
随着公司的项目越来越多,测试版和正式版之间容易混淆,主要是前端是个粗心的小白(你说是吧?陈某惠),经常测试正式版无法正确的区分,导致运营中会出现各种各样的问题,为了解决此问题,突然想到了曾几何时micoya大佬透露的一些姿势,正好今天闲来无事准备来试试
配置 🔗
首先打开github,找到你的项目,点击Settings
然后新建一个webhook,填写您的api地址和密钥
Which events would you like to trigger this webhook?
选择Let me select individual events.
然后下拉选择
Pushes(Git push to a repository.)
完毕后点击 Add webhook
至此,完成了对github的webhook的配置
api接收 🔗
上述配置完成后,编写一个webapi来实现接收github的通知
1[HttpPost]
2[Route("/api/pull")]
3 public async Task<IActionResult> Post()
4 {
5 using var reader = new StreamReader(Request.Body);
6 var payload = await reader.ReadToEndAsync();
7
8 // 验证 GitHub 密钥
9 var signatureWithPrefix = Request.Headers["X-Hub-Signature-256"].ToString();
10 var computedSignature = ComputeSha256Hash(_gitHubSecret, payload);
11 if (!signatureWithPrefix.EndsWith(computedSignature))
12 {
13 return Unauthorized("Invalid signature");
14 }
15
16 // 解析 JSON 数据
17 var jsonDocument = JsonDocument.Parse(payload);
18 var refBranch = jsonDocument.RootElement.GetProperty("ref").GetString();
19 if (string.IsNullOrEmpty(refBranch))
20 {
21 return Ok("no ref");
22 }
23
24 //分支名称
25 var branche = refBranch.Split('/').Last();
26 //仓库名
27 var repositoryName = jsonDocument.RootElement.GetProperty("repository").GetProperty("name").GetString();
28 //克隆地址
29 var cloneUrl = jsonDocument.RootElement.GetProperty("repository").GetProperty("clone_url").GetString();
30 //私有化仓库需要在这里插入git账号和token,https:// 这里是8个长度
31 cloneUrl = cloneUrl.Insert(8, $"{_gitHubAccount}:{_gitHubToken}@");
32 //提交的消息
33 var commitMsg = jsonDocument.RootElement.GetProperty("head_commit").GetProperty("message").GetString();
34
35 //仅在测试版中开放
36 if (branche == "develop" || branche == "dev")
37 {
38 //创建文件夹
39 var path = $"/var/webapi/temp/{repositoryName}";
40
41 //目录存在则拉取更新
42 if (Directory.Exists(path))
43 {
44 //直接拉取更新
45 await RunCommand("git", $"pull origin {branche}", path);
46 }
47 else
48 {
49 //不存在则创建文件夹直接clone
50 await RunCommand("mkdir", $"-p {path}");
51 //拉取命令
52 var gitPullResult = await RunCommand("git", $"clone {cloneUrl} {path}");
53 }
54
55 //切换分支
56 var gitCheckoutResult = await RunCommand("git", $"switch {branche}", path);
57
58 // 运行 NPM 构建
59 var npmInstallResult = await RunCommand("npm", "install", path);
60 var npmBuildResult = await RunCommand("npm", "run build", path);
61
62 //删除原文件
63 await RunCommand("rm", "-r /var/webapi/GaoXinCashShop");
64 //编译后的文件覆盖
65 await RunCommand("mv", $"{path}/dist /var/webapi/GaoXinCashShop");
66
67 return Ok("Dev branch updated and built.");
68 }
69 return Ok("Push not on 'dev' branch, no action taken.");
70 }
71
72
73private static string ComputeSha256Hash(string secret, string payload)
74{
75 using var hmacSha256 = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
76 var hash = hmacSha256.ComputeHash(Encoding.UTF8.GetBytes(payload));
77 var builder = new StringBuilder();
78 foreach (var b in hash)
79 {
80 builder.AppendFormat("{0:x2}", b);
81 }
82 return builder.ToString();
83}
84
85private async Task<string> RunCommand(string command, string arguments, string workingDirectory = null)
86{
87 using var process = new Process
88 {
89 StartInfo = new ProcessStartInfo
90 {
91 FileName = command,
92 Arguments = arguments,
93 RedirectStandardOutput = true,
94 UseShellExecute = false,
95 CreateNoWindow = true,
96 WorkingDirectory = workingDirectory ?? Directory.GetCurrentDirectory()
97 }
98 };
99
100 process.Start();
101 var result = await process.StandardOutput.ReadToEndAsync();
102 process.WaitForExit();
103
104 return result;
105}
上述代码需要自行修改,可以做多个项目的接收以及字典的配置
上述代码所展示的为vue2项目通过推送develop分支到github后自动实现git clone和npm构建以及覆盖更新的操作
如上代码仅供参考,推荐采用消息队列执行,否则github的推送会超时
请注意,上述代码由于采用执行的UseShellExecute为false,所以无法执行一些操作,例如包含*的,所以如果要执行一些复杂操作,要么采用UseShellExecute为true(会导致无法读取响应结果),要么自己编写代码完成
配合企业微信 🔗
git clone和npm构建完成后我们无法实时收到消息,为了解决此问题可以参考使用企业微信的群机器人推送功能
当git clone操作完成和npm编译操作完成后,可以实时推送消息到企业微信群中,这样更方便处理
提示 🔗
- 请自备一些工具,否则git无法clone
- 请自备一些工具,否则npm下载plugin会失败
什么?你不知道工具是什么?那还是别玩了!