基于DotNetty实现自动发布 - 自动检测代码变化
前言
很抱歉没有实现上一篇的目标:一键发布,因为工作量超出了预期,本次只实现了 Git
代码变化检测
已完成的功能
- 解决方案的项目发现与配置
- 首次发布需要手动处理
- 自动检测代码变化并解析出待发布的文件
简要说明
-
只需要填写解决方案的
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
发送到服务器