فهرست منبع

squash! feat: 😁新增项目自动更新模块

喵你个旺呀 1 سال پیش
والد
کامیت
13c92aac14

+ 4 - 6
Admin.NET/Admin.NET.Application/Configuration/Gitee.json → Admin.NET/Admin.NET.Application/Configuration/CDConfig.json

@@ -1,21 +1,19 @@
 {
   "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
 
-  "Gitee": {
+  "CDConfig": {
     "Owner": "jasondom", // gitee用户名
     "Repo": "Admin.NET", // 仓库名
     "Branch": "next", // 分支名
     "AccessToken": "xxxxxxxxxxxxxxxxxxxxxxxxx", // gitee用户授权码
-    "OutputDir": { // 输出目录
-      "FrontEnd": "D:\\Admin.NET\\wwwroot", // 前端输出目录
-      "BackEnd": "D:\\Admin.NET" // 后端输出目录
-    },
     "UpdateInterval": 10, // 最小更新间隔(分钟),-1不限制
     "BackupCount": 10, // 备份文件保留数量
+    "BackendOutput": "D:\\Admin.NET", // 后端输出目录
     "Publish": { // 后端发布选项
       "Configuration": "Release", // 发布环境
       "TargetFramework": "net8.0", // 发布.NET版本
       "RuntimeIdentifier": "linux-x64" // 运行环境
-    }
+    },
+    "ExcludeFiles": ["Configuration\\Database.json"] // 排除文件
   }
 }

+ 11 - 41
Admin.NET/Admin.NET.Core/Option/GiteeOptions.cs → Admin.NET/Admin.NET.Core/Option/CDConfigOptions.cs

@@ -7,9 +7,9 @@
 namespace Admin.NET.Core;
 
 /// <summary>
-/// Gitee CI/CD 配置选项
+/// CI/CD 配置选项
 /// </summary>
-public class GiteeOptions : IConfigurableOptions
+public class CDConfigOptions : IConfigurableOptions
 {
     /// <summary>
     /// 用户名
@@ -31,10 +31,7 @@ public class GiteeOptions : IConfigurableOptions
     /// </summary>
     public string AccessToken { get; set; }
     
-    /// <summary>
-    /// 输出目录配置
-    /// </summary>
-    public OutputDirOptions OutputDir { get; set; }
+
 
     /// <summary>
     /// 更新间隔限制(分钟)-1 不限制
@@ -47,52 +44,25 @@ public class GiteeOptions : IConfigurableOptions
     public int BackupCount { get; set; }
 
     /// <summary>
-    /// 发布配置选项
+    /// 输出目录配置
     /// </summary>
-    public GiteePublishOptions Publish { get; set; }
-}
+    public string BackendOutput { get; set; }
 
-/// <summary>
-/// 项目目录
-/// </summary>
-public class ProjectDirOptions
-{
-    /// <summary>
-    /// 后端目录
-    /// </summary>
-    public string BackEnd { get; set; }
-    
-    /// <summary>
-    /// 前端目录
-    /// </summary>
-    public string FrontEnd { get; set; }
-    
     /// <summary>
-    /// 后端入口项目目录
+    /// 发布配置选项
     /// </summary>
-    public string EntryDir { get; set; }
-}
+    public PublishOptions Publish { get; set; }
 
-/// <summary>
-/// 输出目录
-/// </summary>
-public class OutputDirOptions
-{
-    /// <summary>
-    /// 后端目录
-    /// </summary>
-    public string BackEnd { get; set; }
-    
     /// <summary>
-    /// 前端目录
+    /// 排除文件列表
     /// </summary>
-    public string FrontEnd { get; set; }
+    public List<string> ExcludeFiles { get; set; }
 }
 
 /// <summary>
-/// Gitee发布配置选项
+/// 编译发布配置选项
 /// </summary>
-public class GiteePublishOptions
+public class PublishOptions
 {
     /// <summary>
     /// 发布环境配置

+ 3 - 3
Admin.NET/Admin.NET.Core/Service/Common/SysCommonService.cs

@@ -21,15 +21,15 @@ public class SysCommonService : IDynamicApiController, ITransient
 {
     private readonly IApiDescriptionGroupCollectionProvider _apiProvider;
     private readonly SqlSugarRepository<SysUser> _sysUserRep;
-    private readonly GiteeOptions _giteeOptions;
+    private readonly CDConfigOptions _cdConfigOptions;
 
     public SysCommonService(IApiDescriptionGroupCollectionProvider apiProvider,
         SqlSugarRepository<SysUser> sysUserRep,
-        IOptions<GiteeOptions> giteeOptions)
+        IOptions<CDConfigOptions> giteeOptions)
     {
         _sysUserRep = sysUserRep;
         _apiProvider = apiProvider;
-        _giteeOptions = giteeOptions.Value;
+        _cdConfigOptions = giteeOptions.Value;
     }
 
     /// <summary>

+ 31 - 36
Admin.NET/Admin.NET.Core/Service/Update/SysUpdateService.cs

@@ -17,19 +17,19 @@ public class SysUpdateService : IDynamicApiController, ITransient
     private readonly SqlSugarRepository<SysUser> _sysUserRep;
     private readonly SysOnlineUserService _onlineUserService;
     private readonly SysCacheService _sysCacheService;
-    private readonly GiteeOptions _giteeOptions;
+    private readonly CDConfigOptions _cdConfigOptions;
     private readonly UserManager _userManager;
 
     public SysUpdateService(
         SqlSugarRepository<SysUser> sysUserRep,
         SysOnlineUserService onlineUserService,
-        IOptions<GiteeOptions> giteeOptions,
+        IOptions<CDConfigOptions> giteeOptions,
         SysCacheService sysCacheService,
         UserManager userManager)
     {
         _sysUserRep = sysUserRep;
         _userManager = userManager;
-        _giteeOptions = giteeOptions.Value;
+        _cdConfigOptions = giteeOptions.Value;
         _sysCacheService = sysCacheService;
         _onlineUserService = onlineUserService;
     }
@@ -46,22 +46,24 @@ public class SysUpdateService : IDynamicApiController, ITransient
         try
         {
             await SendMessage("----------------------------从远端仓库部署项目-开始----------------------------");
-            await SendMessage($"仓库地址:https://gitee.com/{_giteeOptions.Owner}/{_giteeOptions.Repo}.git");
-            await SendMessage($"仓库分支:{_giteeOptions.Branch}");
+            await SendMessage($"客户端host:{App.HttpContext.Request.Host}");
+            await SendMessage($"客户端IP:{App.HttpContext.GetRemoteIpAddressToIPv4(true)}");
+            await SendMessage($"仓库地址:https://gitee.com/{_cdConfigOptions.Owner}/{_cdConfigOptions.Repo}.git");
+            await SendMessage($"仓库分支:{_cdConfigOptions.Branch}");
 
             await SendMessage("项目备份...");
             // TODO 备份项目
 
             // 获取解压后的根目录
-            var rootPath = Path.GetFullPath(Path.Combine(_giteeOptions.OutputDir.BackEnd, ".."));
-            var tempDir = Path.Combine(rootPath, $"{_giteeOptions.Repo}-{_giteeOptions.Branch}");
+            var rootPath = Path.GetFullPath(Path.Combine(_cdConfigOptions.BackendOutput, ".."));
+            var tempDir = Path.Combine(rootPath, $"{_cdConfigOptions.Repo}-{_cdConfigOptions.Branch}");
 
             await SendMessage("清理旧文件...");
-            TryDeleteFileOrDir(tempDir);
+            FileHelper.TryDelete(tempDir);
 
             await SendMessage("拉取远端代码...");
-            var stream = await GiteeHelper.DownloadRepoZip(_giteeOptions.Owner, _giteeOptions.Repo,
-                _giteeOptions.AccessToken, _giteeOptions.Branch);
+            var stream = await GiteeHelper.DownloadRepoZip(_cdConfigOptions.Owner, _cdConfigOptions.Repo,
+                _cdConfigOptions.AccessToken, _cdConfigOptions.Branch);
 
             await SendMessage("文件包解压...");
             using ZipArchive archive = new(stream, ZipArchiveMode.Read, leaveOpen: false);
@@ -70,19 +72,31 @@ public class SysUpdateService : IDynamicApiController, ITransient
             // 项目目录
             var backendDir = "Admin.NET";
             var entryProjectName = "Admin.NET.Web.Entry";
+            var tempOutput = Path.Combine(_cdConfigOptions.BackendOutput, "temp");
 
             await SendMessage("编译项目...");
-            await SendMessage($"发布版本:{_giteeOptions.Publish.Configuration}");
-            await SendMessage($"目标框架:{_giteeOptions.Publish.TargetFramework}");
-            await SendMessage($"运行环境:{_giteeOptions.Publish.RuntimeIdentifier}");
-            var option = _giteeOptions.Publish;
+            await SendMessage($"发布版本:{_cdConfigOptions.Publish.Configuration}");
+            await SendMessage($"目标框架:{_cdConfigOptions.Publish.TargetFramework}");
+            await SendMessage($"运行环境:{_cdConfigOptions.Publish.RuntimeIdentifier}");
+            var option = _cdConfigOptions.Publish;
             var adminNetDir = Path.Combine(tempDir, backendDir);
-            var args =
-                $"publish \"{entryProjectName}\" -c {option.Configuration} -f {option.TargetFramework} -r {option.RuntimeIdentifier} --output \"{_giteeOptions.OutputDir.BackEnd}\"";
+            var args = $"publish \"{entryProjectName}\" -c {option.Configuration} -f {option.TargetFramework} -r {option.RuntimeIdentifier} --output \"{tempOutput}\"";
             await RunCommandAsync("dotnet", args, adminNetDir);
 
+            await SendMessage("移动wwwroot目录...");
+            var wwwrootDir = Path.Combine(adminNetDir, entryProjectName, "wwwroot");
+            FileHelper.CopyDirectory(wwwrootDir, Path.Combine(tempOutput, "wwwroot"), true);
+
+            // 删除排除文件
+            await SendMessage("删除排除文件...");
+            foreach (var file in _cdConfigOptions.ExcludeFiles ?? new()) FileHelper.TryDelete(Path.Combine(tempOutput, file));
+
+            // 将临时文件移动到正式目录
+            FileHelper.CopyDirectory(tempOutput, _cdConfigOptions.BackendOutput, true);
+
             await SendMessage("清理文件...");
-            TryDeleteFileOrDir(tempDir);
+            FileHelper.TryDelete(tempOutput);
+            FileHelper.TryDelete(tempDir);
 
             await SendMessage("----------------------------从远端仓库部署项目-结束----------------------------");
         }
@@ -149,23 +163,4 @@ public class SysUpdateService : IDynamicApiController, ITransient
         }
         await process.WaitForExitAsync();
     }
-
-    /// <summary>
-    /// 尝试删除文件/目录
-    /// </summary>
-    /// <param name="path"></param>
-    /// <returns></returns>
-    private void TryDeleteFileOrDir(string path)
-    {
-        try
-        {
-            if (string.IsNullOrEmpty(path)) return;
-            if (Directory.Exists(path)) Directory.Delete(path, recursive: true);
-            else File.Delete(path);
-        }
-        catch (Exception)
-        {
-            // ignored
-        }
-    }
 }

+ 65 - 0
Admin.NET/Admin.NET.Core/Utils/FileHelper.cs

@@ -0,0 +1,65 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+// 
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+// 
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 文件帮助类
+/// </summary>
+public static class FileHelper
+{
+    /// <summary>
+    /// 尝试删除文件/目录
+    /// </summary>
+    /// <param name="path"></param>
+    /// <returns></returns>
+    public static bool TryDelete(string path)
+    {
+        try
+        {
+            if (string.IsNullOrEmpty(path)) return false;
+            if (Directory.Exists(path)) Directory.Delete(path, recursive: true);
+            else File.Delete(path);
+            return true;
+        }
+        catch (Exception)
+        {
+            // ignored
+            return false;
+        }
+    }
+
+    /// <summary>
+    /// 复制目录
+    /// </summary>
+    /// <param name="sourceDir"></param>
+    /// <param name="destinationDir"></param>
+    /// <param name="overwrite"></param>
+    public static void CopyDirectory(string sourceDir, string destinationDir, bool overwrite = false)
+    {
+        // 检查源目录是否存在
+        if (!Directory.Exists(sourceDir)) throw new DirectoryNotFoundException("Source directory not found: " + sourceDir);
+
+        // 如果目标目录不存在,则创建它
+        if (!Directory.Exists(destinationDir)) Directory.CreateDirectory(destinationDir!);
+
+        // 获取源目录下的所有文件并复制它们
+        foreach (string file in Directory.GetFiles(sourceDir))
+        {
+            string name = Path.GetFileName(file);
+            string dest = Path.Combine(destinationDir, name);
+            File.Copy(file, dest, overwrite);
+        }
+
+        // 递归复制所有子目录
+        foreach (string directory in Directory.GetDirectories(sourceDir))
+        {
+            string name = Path.GetFileName(directory);
+            string dest = Path.Combine(destinationDir, name);
+            CopyDirectory(directory, dest, overwrite);
+        }
+    }
+}

+ 1 - 1
Admin.NET/Admin.NET.Web.Core/ProjectOptions.cs

@@ -37,7 +37,7 @@ public static class ProjectOptions
         services.AddConfigurableOptions<CryptogramOptions>();
         services.AddConfigurableOptions<SMSOptions>();
         services.AddConfigurableOptions<EventBusOptions>();
-        services.AddConfigurableOptions<GiteeOptions>();
+        services.AddConfigurableOptions<CDConfigOptions>();
         services.Configure<IpRateLimitOptions>(App.Configuration.GetSection("IpRateLimiting"));
         services.Configure<IpRateLimitPolicies>(App.Configuration.GetSection("IpRateLimitPolicies"));
         services.Configure<ClientRateLimitOptions>(App.Configuration.GetSection("ClientRateLimiting"));