前言
很抱歉沒有實現上一篇的目標:一鍵釋出,因為工作量超出了預期,本次只實現了 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
傳送到伺服器