分享

快速打造一个MINI自动发布系统

 风声之家 2021-05-12

dotNET跨平台 今天

以下文章来源于桂迹 ,作者桂素伟

前情提要:因为项目特点,需要在自己的服务器上集成测试,而不是用github的DevOpt体系;再有就是服务器是windows的;项目仓库在github上;并且项目是asp.net core的项目;开发人员一枚。以前的做法就是发布后,把执行码复制在服务器上启动;后来就是在服务器写了个bat,运行bat,完成clone项目,发布项目,运行项项目;再后台就是写了个web服务,让github项目感知到推送后,通知web服务,web服务执行这个bat。

在这里面,有几个要素:

  • bat:完成代码clone,发布,运行(其实真实中还要完成对运行的项目进行关闭,清理等工作,以方便展开最新一次的clone,发布,运行)
  • web服务
  • github通知配置

先看bat,命令如下,就是关闭运行中的项目,清理目录,clone项目,进入项目目录,发布项目,然后运行项目











taskkill /f /im 项目名称.exetimeout 1 >NUL@RD /S /Q "C:\项目名称\项目目录"cd  C:\项目名称git clone https://用户名:密码@github.com/用户名/项目名称.gitcd  C:\项目名称\项目目录dotnet publish -o C:\项目名称\pubtimeout 1>NULcd C:\项目名称\pub项目名称.exe

再看一下web服务,就是等待github通知,收到通知后,获取key参数,然后验证这个调用通知是否有效(最好和https),再调用bat

appsettings.json

projects的配置目的是实现一个web服务,可以接收多个项目的通知,然后针对不对的项目进行发布和运行,当github通知的时间,会在参数key中告诉web服务要执行那个project,这里与web服务的key参数结合使用。


















{  "urls": "http://*:6789",  "Logging": {    "LogLevel": {      "Default": "Information",      "Microsoft": "Warning",      "Microsoft.Hosting.Lifetime": "Information"    }  },  "AllowedHosts": "*",  "Projects": [    {      "key": "memall",      "BATPath": "C://MeMall/MeMall_Start.bat",      "Secret": "e0f0d18348fbcb090fa17f9fbc638a8be56be3ab"    }  ]}

homecontrolloer.cs文件

其中IsGitHubSignatureSHA1和 IsGitHubSignatureSHA256是两种验证方式,可以选其中的一种进行验证就可以,验证成功才能执行bat,这里同时用两种验证方式,只是为了演示而以。







































































































































































using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.Logging;using Microsoft.Extensions.Primitives;using System;using System.Collections.Generic;using System.Diagnostics;using System.IO;using System.Linq;using System.Security.Cryptography;using System.Text;using System.Text.RegularExpressions;using System.Threading.Tasks;
namespace GitHubNotice.Controllers{ [ApiController] [Route("[controller]")] public class HomeController : ControllerBase { private readonly IEnumerable<Project> _projects; private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger, IConfiguration configuration) { _projects = configuration.GetSection("Projects").Get<List<Project>>(); _logger = logger; }
[HttpPost("/")] public async Task<IActionResult> Notice() { _logger.LogInformation($"应用收到github Notice"); Request.Headers.TryGetValue("X-GitHub-Delivery", out StringValues gitHubDeliveryId); Request.Headers.TryGetValue("X-GitHub-Event", out StringValues gitHubEvent); _logger.LogInformation($"收到github通知事务:X-GitHub-Delivery:{gitHubDeliveryId},X-GitHub-Event:{gitHubEvent}"); Request.Headers.TryGetValue("X-Hub-Signature", out StringValues gitHubSignature); Request.Headers.TryGetValue("X-Hub-Signature-256", out StringValues gitHubSignature256); var reader = new StreamReader(Request.Body, Encoding.UTF8); var bodyContent = await reader.ReadToEndAsync(); var key = GetMark(bodyContent); var rgx = new Regex(@"^[a-zA-Z]+$"); if (!string.IsNullOrWhiteSpace(key) && !rgx.IsMatch(key)) { _logger.LogError($"key={key} 错误"); return BadRequest(); } else { var project = _projects.SingleOrDefault(s => s.Key == key); if (project != null) { var resultSHA256 = IsGitHubSignatureSHA256(project.Secret, bodyContent, gitHubSignature256); var resultSHA1 = IsGitHubSignatureSHA1(project.Secret, bodyContent, gitHubSignature); _logger.LogInformation($"SHA1={resultSHA1},SHA256={resultSHA256}"); if (resultSHA1 && resultSHA256) { var p = new Process(); p.StartInfo.CreateNoWindow = true; p.StartInfo.UseShellExecute = true; p.StartInfo.FileName = project.BATPath; p.Start(); p.Close(); _logger.LogInformation($"github通知成功"); return Ok(); } else { _logger.LogError("认证错误"); return Unauthorized(); } } else { _logger.LogError($"检查配置文件Projects是否与github中的Payload URL相匹配"); return BadRequest(); } } } /// <summary> /// 获取匹配项目的key /// </summary> /// <param name="text"></param> /// <returns></returns> string GetMark(string text) { var arry = text.Split('&'); foreach (var item in arry) { if (item.Contains("key=")) { return item.Split('=')[1]; } } return ""; } /// <summary> /// sha1 /// </summary> /// <param name="seckey"></param> /// <param name="bodyContent"></param> /// <param name="signatureSHA1"></param> /// <returns></returns> static bool IsGitHubSignatureSHA1(string seckey, string bodyContent, string signatureSHA1) { if (string.IsNullOrWhiteSpace(bodyContent)) throw new ArgumentNullException(nameof(bodyContent)); if (string.IsNullOrWhiteSpace(signatureSHA1)) throw new ArgumentNullException(nameof(signatureSHA1));
var signature = signatureSHA1.Replace("sha1=", ""); var secret = Encoding.ASCII.GetBytes(seckey); var payloadBytes = Encoding.ASCII.GetBytes(bodyContent);
using (var hmacsha1 = new HMACSHA1(secret)) { var hash = hmacsha1.ComputeHash(payloadBytes); var hashString = ToHexString(hash); if (hashString.Equals(signature)) return true; } return false;
static string ToHexString(byte[] bytes) { var builder = new StringBuilder(bytes.Length * 2); foreach (byte b in bytes) { builder.AppendFormat("{0:x2}", b); } return builder.ToString(); } }

/// <summary> /// X-Hub-Signature-256 /// </summary> /// <param name="secret"></param> /// <param name="bodyContent"></param> /// <param name="signatureSHA256"></param> /// <returns></returns> static bool IsGitHubSignatureSHA256(string secret, string bodyContent, string signatureSHA256) { if (string.IsNullOrWhiteSpace(bodyContent)) throw new ArgumentNullException(nameof(bodyContent)); if (string.IsNullOrWhiteSpace(signatureSHA256)) throw new ArgumentNullException(nameof(signatureSHA256));
var secretBytes = Encoding.UTF8.GetBytes(secret); var hasher = new HMACSHA256(secretBytes); var data = Encoding.UTF8.GetBytes(bodyContent); var computedSignature = BitConverter.ToString(hasher.ComputeHash(data)).Replace("-", "").ToLower(); return computedSignature == signatureSHA256.Replace("sha256=", ""); } } /// <summary> /// 项目实体 /// </summary> public class Project { public string Key { get; set; } public string BATPath { get; set; } public string Secret { get; set; } }}

最后就是github的Webhooks,通过配置,当有人推送代码时,会通知web服务,方便进行拉取构建。

图片

其实这就是一个极其简单,代替手工发布的脚本级别工具,特点就是小巧,灵活,简单,可以随心所欲的改;如果是大团队,或更多的要求,比如集成测试,打包镜像等,可以选用比较成熟的产品(可以搜索CICD工具,这里不作广告了)来使用,相对来说也需要学习成本。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约