|
前言
上一篇,我只实现了一键检测代码变化,本篇才是真正的实现了一键打包发布
效果图
客户端打包待发布文件
- /// <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 服务, 这个也很简单, 我就不发了, 大家自行实现吧, 完结~
来源:https://www.cnblogs.com/broadm/archive/2023/12/11/17894063.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|