日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

基于DotNetty实现自动发布 - 实现一键打包发布

發布時間:2023/12/24 windows 32 coder
生活随笔 收集整理的這篇文章主要介紹了 基于DotNetty实现自动发布 - 实现一键打包发布 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

上一篇,我只實現了一鍵檢測代碼變化,本篇才是真正的實現了一鍵打包發布

效果圖



客戶端打包待發布文件

    /// <summary>
    /// 把多個文件添加到壓縮包 (保留文件夾層級關系)
    /// </summary>
    public static async Task<ZipFileResult> CreateZipAsync(IEnumerable<ZipFileInfo> zipFileInfo)
    {
        return await Task.Run(() =>
        {
            var zipDir = EnsureZipDirCreated();
            var zipFileName = $"{DateTime.Now:yyyyMMdd_HHmmss_}{Guid.NewGuid()}.zip";
            var zipPath = Path.Combine(zipDir, zipFileName);
            using var archive = ZipFile.Open(zipPath, ZipArchiveMode.Update);
            foreach (var item in zipFileInfo)
            {
                archive.CreateEntryFromFile(item.FileAbsolutePath, item.FileRelativePath, CompressionLevel.SmallestSize);
            }
            return new ZipFileResult() { FullFileName = zipPath, FileName = zipFileName };
        });
    }

客戶端封裝 NettyMessage

            //讀取zip字節數組,填充到 NettyMessage 的 Body
            var body = await File.ReadAllBytesAsync(zipResult.FullFileName);

            //NettyHeader
            var header = new DeployRequestHeader()
            {
                Files = PublishFiles,
                SolutionName = SolutionName,
                ProjectName = webProject!.ProjectName,
                ZipFileName = zipResult.FileName,
            };

            var nettyMessage = new NettyMessage { Header = header, Body = body };

            //創建 NettyClient
            Logger.Info("開始發送");
            using var nettyClient = new NettyClient(webProject.ServerIp, webProject.ServerPort);
            await nettyClient.SendAsync(nettyMessage);
            Logger.Info("完成發送");

            Growl.SuccessGlobal($"發布成功");

            //保存發布記錄
            await solutionRepo.SaveFirstPublishAsync(SolutionId, SolutionName, lastGitCommit!.Sha);
            Growl.SuccessGlobal($"操作成功");

            quickDeployDialog?.Close();

NettyHeader 設計

具體實現是 DeployRequestHeader, 繼承自 NettyHeader, 保存待發布文件集合,項目名稱,解決方案名稱, zip 文件名稱等

/// <summary>
/// 發布請求頭部
/// </summary>
public class DeployRequestHeader : NettyHeader
{
    public DeployRequestHeader() : base("Deploy/Run") { }
    public List<DeployFileInfo> Files { get; set; } = [];
    public string ProjectName { get; set; } = string.Empty;
    public string SolutionName { get; set; } = string.Empty;
    public string ZipFileName { get; set; } = string.Empty;
}

服務端處理

  • 解壓 zip
  • 備份目標文件(存在才備份)
  • 替換目標文件(不存在則新建)
/// <summary>
/// 執行服務端發布
/// </summary>
/// <param name="model"></param>
public void Run(DeployRequestHeader model)
{
    Logger.Warn($"收到客戶端的消息: {model.ToJsonString(true)}");

    var configs = NettyServer.AppHost.Services.GetRequiredService<IOptions<List<ProjectConfig>>>();
    var projectConfig = configs.Value.FirstOrDefault(a => a.ProjectName == model.ProjectName);
    if (projectConfig == null)
    {
        Logger.Error("請現在服務器項目的appsettings.json中配置項目信息");
        return;
    }

    var zipBytes = Request.Body;
    if (zipBytes == null || zipBytes.Length == 0)
    {
        Logger.Error("ZipBytes為空");
        return;
    }

    var zipFileName = model.ZipFileName;
    if (string.IsNullOrEmpty(zipFileName))
    {
        Logger.Error("ZipFileName為空");
        return;
    }

    //解壓
    var zipDir = ZipHelper.UnZip(zipBytes, zipFileName);

    Logger.Info($"解壓成功: {zipDir}");

    //備份并覆蓋舊文件
    DoPublish(model.Files, zipDir, zipFileName, projectConfig);

    Logger.Info($"發布成功: {zipDir}");
}
/// <summary>
/// 備份并覆蓋舊文件
/// </summary>
private static void DoPublish(List<DeployFileInfo> files, string zipDir, string zipFileName, ProjectConfig projectConfig)
{
    try
    {
        //先創建備份文件夾
        var backupDir = EnsureBackupDirCreated(zipFileName);

        //遍歷每個待發布的文件,依次先備份再替換
        foreach (DeployFileInfo file in files)
        {
            //文件相對路徑(相對于待發布的項目根目錄,也是相對于解壓后的根目錄)
            var relativeFilePath = file.PublishFileRelativePath;

            //源文件路徑(解壓后的文件路徑)
            var sourceFileName = Path.Combine(zipDir, relativeFilePath);

            //待發布的文件路徑 (服務器真實文件路徑)
            var destFileName = Path.Combine(projectConfig.ProjectDir, relativeFilePath);

            //服務器已存在此文件,先執行備份
            if (File.Exists(destFileName))
            {
                //備份文件路徑
                var backupFileName = Path.Combine(backupDir, relativeFilePath);
                //確保創建備份文件夾
                var backupFileDir = Path.GetDirectoryName(backupFileName);
                if (!Directory.Exists(backupFileDir))
                {
                    Directory.CreateDirectory(backupFileDir!);
                }
                File.Copy(destFileName, backupFileName);
            }
            else
            {
                //服務器不存在此文件,先創建文件夾層級(比如你新加了一個頁面demo.aspx,需要發布到服務器對應的位置)
                var destFileDir = Path.GetDirectoryName(destFileName);
                if (!Directory.Exists(destFileDir))
                {
                    Directory.CreateDirectory(destFileDir!);
                }
            }

            //替換服務器文件
            File.Copy(sourceFileName, destFileName, true);
        }
    }
    catch (Exception ex)
    {
        Logger.Error(ex.ToString());
    }
}

總結

至此,我已經完成了自動發布項目的主體功能,實現自動檢測代碼變化,自動一鍵打包發布, 不足的地方有: 第一次發布需要手動處理, 項目也需要手動編譯,并配置輸出目錄,但是我相信,這些都不是問題,只要有思路,都是可以解決的,我主要分享下我的實現步驟

注意

1. 本項目目前只支持 .net framework 的單體 Web 項目
2. 客戶端和服務端均是 Windows 服務器
3. 線上項目是 IIS 部署的
4. 代碼可能存在 BUG,大家發現可以自行解決,或者聯系我,我后面不準備繼續維護這個項目,畢竟主要是學習分享用的~~~

代碼倉庫

項目暫且就叫 OpenDeploy

  • OpenDeploy: https://gitee.com/broadm-dotnet/OpenDeploy

歡迎大家拍磚,Star

下一步

服務端目前是控制臺實現, 可以部署為 Windows 服務, 這個也很簡單, 我就不發了, 大家自行實現吧, 完結~

總結

以上是生活随笔為你收集整理的基于DotNetty实现自动发布 - 实现一键打包发布的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。