基于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吧
欢迎大家拍砖,Star
下一步
服务端目前是控制台实现, 可以部署为 Windows 服务, 这个也很简单, 我就不发了, 大家自行实现吧, 完结~
基于DotNetty实现自动发布 - 实现一键打包发布的更多相关文章
- 使用jenkins一键打包发布vue项目
jenkins的安装 Jenkins是一款开源 CI&CD 软件,用于自动化各种任务,包括构建.测试和部署软件. Jenkins 支持各种运行方式,可通过系统包.Docker 或者通过一个独立 ...
- linux自动更新代码,打包发布
1.安装svn yum install subversion 2.安装 maven 下载:百度云盘地址为 http://pan.baidu.com/s/1nuKQGjv 解压 tar -zxvf ap ...
- 带你了解基于Ploto构建自动驾驶平台
摘要:华为云Solution as Code推出基于Ploto构建自动驾驶平台解决方案. 本文分享自华为云社区<基于Ploto构建自动驾驶平台>,作者:阿米托福 . 2022年6月15日, ...
- Ant自动编译打包&发布 android项目
Eclipse用起来虽然方便,但是编译打包android项目还是比较慢,尤其将应用打包发布到各个渠道时,用Eclipse手动打包各种渠道包就有点不切实际了,这时候我们用到Ant帮我们自动编译打包了. ...
- Andorid进阶7—— Ant自动编译打包&发布 android项目
http://www.cnblogs.com/tt_mc/p/3891546.html Eclipse用起来虽然方便,但是编译打包android项目还是比较慢,尤其将应用打包发布到各个渠道时,用Ecl ...
- 使用 maven 自动将源码打包并发布
1.maven-source-plugin 访问地址 在 pom.xml 中添加 下面的 内容,可以 使用 maven 生成 jar 的同时 生成 sources 包 <plugin> & ...
- maven 聚合的含义是父类打包 ,清理等 则子类自动打包;也就是一键打包 方便服务
maven 聚合的含义是父类打包 ,清理等 则子类自动打包:也就是一键打包 方便服务
- 使用release自动打包发布正式版详细教程
昨天写了个release插件的版本管理,今天就在自动发布过程中遇到了许多坑,只能再写一篇自动发布详细教程,纪念我那昨日逝去的青春 (╥ _ ╥`) release正常打包发布流程按照如下几个阶段: C ...
- 使用VS中自带的一键打包功能将我们的ASP.NET Core类库打包并将程序包(类库)发布到NuGet平台上进行管理
本章将和大家简单分享下如何使用VS中自带的一键打包功能将我们的ASP.NET Core类库打包并将程序包(类库)发布到NuGet平台上进行管理. 一.注册并登录NuGet平台 NuGet官网:http ...
- 发布nuget包的正确姿势---cicd自动打包发布nuget包
最轻便的发布nuget包方式,方便cicd自动打包发布nuget包 首先新建项目 项目名随便取,这里就叫它GuiH.ClassLibrary 默认即可,需要改目标版本时,等创建好再改 项目创建好了 随 ...
随机推荐
- [ABC131E] Friendships
2023-01-30 题目 题目传送门 翻译 翻译 难度&重要性(1~10):4 题目来源 AtCoder 题目算法 找规律,构造 解题思路 先构造一个菊花图为最大边的图,再依次连边减小k. ...
- 当小白遇到FullGC
起初没有人在意这场GC,直到它影响到了每一天! 前言 本文记录了一次排查FullGC导致的TP99过高过程,介绍了一些排查时思路,线索以及工具的使用,希望能够帮助一些新手在排查问题没有很好的思路时,提 ...
- 【LaTeX】制作 PPT(更新中)
目录 Beamer 模板 特性 frame 与 slide \pause itemize 中的尖括号 <strat-end> 参考资料 Beamer 模板 PPT 推荐用 Beamer 模 ...
- ArcMap中矢量数据修改标注Label的方法
本文介绍在ArcMap软件中,修改图层标签(Label)所显示字段与具体显示内容的方法. 在之前的文章中,我们看到了ArcMap中修改图层标签的重要性:可是,如何自定义图层的标签内容呢? ...
- 文心一言 VS 讯飞星火 VS chatgpt (91)-- 算法导论8.3 4题
四.用go语言,说明如何在 O(n) 时间内,对 0 到 $n^3-1$ 区间内的n个整数进行排序. 文心一言: 在 O(n) 时间内对 0 到 n^3-1 区间内的 n 个整数进行排序,可以使用基数 ...
- 利用别名简化进入docker容器数据库的操作
之前研究docker和数据库的交互,越发对docker这个东西喜爱了.因为平常偶尔会用到各类数据库测试环境验证一些想法,需要进一步简化进入到这些环境的步骤. 比如我现在有三套docker容器数据库测试 ...
- 从DevOps实践落地的角度谈谈“流程”和“规范"的反模式
最近在经历的一些事情,让我突发灵感,觉得要写点关于DevOps体系建设过程中的"流程规范",记录下来. 如何解读"流程规范" 谈到DevOps落地,无一例外都会 ...
- Building-Mobile-Apps-with-Ionic-2中文翻译工作
最近没啥工作量, 然后学完了这本书, 接着又茫然找不到该干啥, 所以想着何不翻译这个书呢. 这本书首先给我们普及了Ionic 2的基础知识, Ionic 2和Ionic 1有本质上的区别, Ionic ...
- 关于oop的一点回忆
昨天在一个程序员行业群里看到别人发了一条消息, 大意是:要做好封装啦,不要随便用public啦,不要随便改别人代码啦. 说的好像就是我,因为,我这辈子最后悔的一件事情之一就是手贱改动别人代码. 那大概 ...
- Ds100p -「数据结构百题」11~20
11.P3203 [HNOI2010]弹飞绵羊 某天,\(Lostmonkey\) 发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏. 游戏一开始,\(Lostmonkey ...