梦想博客

Github使用Webhook功能实现自动更新

calendar 2023/12/11
refresh-cw 2023/12/14
1231字,3分钟
分类: github
tag github;

前言 🔗

随着公司的项目越来越多,测试版和正式版之间容易混淆,主要是前端是个粗心的小白(你说是吧?陈某惠),经常测试正式版无法正确的区分,导致运营中会出现各种各样的问题,为了解决此问题,突然想到了曾几何时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会失败

什么?你不知道工具是什么?那还是别玩了!


分类