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


      前情提要:因为项目特点,需要在自己的服务器上集成测试,而不是用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 项目名称.exe
    timeout 1 >NUL
    @RD /S /Q "C:\项目名称\项目目录"
    cd  C:\项目名称
    git clone https://用户名:密码@github.com/用户名/项目名称.git
    cd  C:\项目名称\项目目录
    dotnet publish -o C:\项目名称\pub
    timeout 1>NUL
    cd 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工具,这里不作广告了)来使用,相对来说也需要学习成本。

      想要更快更方便的了解相关知识,可以关注微信公众号 
     

     

  • 相关阅读:
    AN BD FD DD CD UT CT TT IT ST UAT OP
    log4j
    重构代码
    with as sql的优化
    svn locked,并且无法clean up 的解决方法
    去掉Eclipse中没用的workspace
    getHibernateTemplate()的get方法
    Java反射
    windows 右键新建html文档
    fiddler 针对单个接口打断点
  • 原文地址:https://www.cnblogs.com/axzxs2001/p/15864237.html
Copyright © 2020-2023  润新知