基于DotNetty实现自动发布 – 自动检测代码变化

前言

很抱歉没有实现上一篇的目标:一键发布,因为工作量超出了预期,本次只实现了 Git 代码变化检测

已完成的功能

  • 解决方案的项目发现与配置
  • 首次发布需要手动处理
  • 自动检测代码变化并解析出待发布的文件

基于DotNetty实现自动发布 - 自动检测代码变化
基于DotNetty实现自动发布 - 自动检测代码变化
基于DotNetty实现自动发布 - 自动检测代码变化

简要说明

  • 只需要填写解决方案的 Git 仓储路径即可自动发现项目 (通过查找 .csproj 文件实现)

  • 自动发现 Web 项目 (通过判断项目根目录是否包含 Web.config 实现) PS: 只支持 .NET Framework

  • 需要配置 Web 项目的发布目录, 编译还需要手动执行

  • 首次发布需要手动执行, 然后保存此次发布对应的 Git 提交 ID

  • 后续发布,可以根据上次发布记录,自动解析出待待发布的文件

部分代码

发现解决方案

private static Solution DetectSolution(string gitRepoPath) {     string[] solutionFilePaths = Directory.GetFiles(gitRepoPath, "*.sln", SearchOption.AllDirectories);     if (solutionFilePaths == null || solutionFilePaths.Length == 0)     {         throw new Exception("未找到解决方案");     }     string[] projectFilePaths = Directory.GetFiles(gitRepoPath, "*.csproj", SearchOption.AllDirectories);     if (projectFilePaths == null || projectFilePaths.Length == 0)     {         throw new Exception("未找到项目");     }      var solutionFilePath = solutionFilePaths[0];     var solutionDir = Path.GetDirectoryName(solutionFilePath);     var solutionName = Path.GetFileNameWithoutExtension(solutionFilePath);      var solution = new Solution     {         GitRepositoryPath = gitRepoPath,         SolutionDir = solutionDir!,         SolutionName = solutionName     };      foreach (var projectFilePath in projectFilePaths)     {         var projectDir = Path.GetDirectoryName(projectFilePath);         var projectName = Path.GetFileNameWithoutExtension(projectFilePath);         var webConfigFiles = Directory.GetFiles(projectDir!, "web.config", SearchOption.TopDirectoryOnly);         var project = new Project         {             ProjectDir = projectDir!,             ProjectName = projectName,             IsWeb = webConfigFiles != null && webConfigFiles.Length > 0,             SolutionName = solutionName,             ReleaseDir = string.Empty         };         solution.Projects.Add(project);     }     return solution; } 

获取自上次发布以来的改动

public static List<PatchEntryChanges> GetChangesSinceLastPublish(string repoPath, string? lastCommitId = null) {     var repo = GetRepo(repoPath);      //获取上次发布的提交     Commit? lastCommit = null;     if (!string.IsNullOrEmpty(lastCommitId))     {         lastCommit = repo.Lookup<Commit>(lastCommitId);         if (lastCommit == null)         {             throw new Exception("无法获取上次发布的提交记录");         }     }      //获取自上次提交以来的改动     var diff = repo.Diff.Compare<Patch>(lastCommit?.Tree, DiffTargets.Index);     return [.. diff]; } 

从 Git 修改记录提取出待发布文件

private List<DeployFileInfo> GetPublishFiles(IEnumerable<string> changedFilePaths) {     var fileInfos = new List<DeployFileInfo>(changedFilePaths.Count());     foreach (string changedPath in changedFilePaths)     {         var fi = DeployFileInfo.Create(changedPath);         if (fi.IsUnKnown) continue;         fileInfos.Add(fi);     }     foreach (var fi in fileInfos)     {         fi.ChangedFileAbsolutePath = Path.Combine(GitRepositoryPath, fi.ChangedFileRelativePath);          //所属项目         var project = Projects             .Where(a => fi.ChangedFileRelativePath.Contains(a.ProjectName, StringComparison.OrdinalIgnoreCase))             .FirstOrDefault();         if (project == null) continue;          fi.ProjectName = project.ProjectName;         if (fi.IsDLL)         {             fi.FileName = $"{project.ProjectName}.dll";             fi.PublishFileRelativePath = $"bin\{fi.FileName}";         }         else         {             fi.PublishFileRelativePath = fi.ChangedFileAbsolutePath.Replace(project.ProjectDir, "").TrimStart(Path.DirectorySeparatorChar);         }         fi.PublishFileAbsolutePath = Path.Combine(webProject!.ReleaseDir, fi.PublishFileRelativePath);          //Logger.Info(fi.ToJsonString(true));     }     //按照 PublishFileAbsolutePath 去重     return fileInfos.Distinct(new DeployFileInfoComparer()).ToList(); } 

设置项目发布路径

private async Task OkSetProjectReleaseDir() {     if (string.IsNullOrEmpty(ReleaseDir) || !Directory.Exists(ReleaseDir))     {         Growl.ClearGlobal();         Growl.ErrorGlobal("请正确设置项目发布路径");         return;     }      var solutionRepo = Program.AppHost.Services.GetRequiredService<SolutionRepository>();     await solutionRepo.UpdateProjectReleaseDir(Id, ReleaseDir);      setProjectReleaseDirDialog?.Close();      Growl.SuccessGlobal("操作成功"); } 

总结

本篇主要实现了 Git 代码变化的自动检测

代码仓库

项目暂且就叫 OpenDeploy

欢迎大家拍砖,Star

下一步

计划下一步,实现一键发布,把待发布的文件一次性打包通过 DotNetty 发送到服务器

发表评论

评论已关闭。

相关文章