跳转到主内容

SeatFlow 构建命令、多平台发布脚本、确定性构建、GitCommit 自动生成和 SHA256 校验表

构建与发布

构建

环境要求

  • .NET 10 SDK
  • Windows / macOS(需要Apple开发者账号) / Linux
  • 推荐 IDE:Rider、VS Code + C# 扩展、Visual Studio 2022+

构建命令

# 构建全部 9 个项目(使用 .slnx)
dotnet build

# 构建特定项目
dotnet build src/SeatFlow.Presentation.Avalonia/SeatFlow.Presentation.Avalonia.csproj

# 还原 NuGet 依赖
dotnet restore

解决方案结构

SeatFlow.slnx 使用新的 XML 格式(.slnx),包含 9 个项目:

项目 用途
SeatFlow.Core 领域核心
SeatFlow.Core.Tests Core 层测试
SeatFlow.Contracts 跨层契约
SeatFlow.Application 应用层
SeatFlow.Application.Tests Application 层测试
SeatFlow.Infrastructure 基础设施
SeatFlow.Infrastructure.Tests Infrastructure 层测试
SeatFlow.Plugins.Sdk 插件 SDK
SeatFlow.Presentation.Avalonia Avalonia 桌面应用

项目配置要点

关键 csproj 设置(SeatFlow.Presentation.Avalonia.csproj):

<!-- 输出文件名 -->
<AssemblyName>SeatFlow</AssemblyName>
<!-- 输出 EXE 为 SeatFlow.exe,而非 SeatFlow.Presentation.Avalonia.exe -->

<!-- 编译绑定 -->
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>

<!-- 抑制 DI 构造函数警告 -->
<NoWarn>$(NoWarn);AVLN3001</NoWarn>

<!-- Designer.cs 条件编译 -->
<Compile Remove="Lang\Resources.Designer.cs"
  Condition="!Exists('Lang\Resources.Designer.cs')" />

<!-- Windows DPI 感知 -->
<ApplicationManifest>app.manifest</ApplicationManifest>

确定性构建

项目配置了确定性构建,确保相同源码始终产生相同的输出哈希:

<Deterministic>true</Deterministic>
<PathMap>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)'))=./</PathMap>
  • <Deterministic>true</Deterministic>:启用确定性编译,相同源码 → 相同 IL
  • <PathMap>:将绝对路径映射为相对路径 ./,消除构建机器的路径差异

排查非确定性构建

如果多次 dotnet build 产生不同的输出哈希,检查以下常见原因:

  • 自动生成的 GitCommit.g.cs 是否包含提交哈希(每次提交不同,但相同提交应相同)
  • NuGet 包还原是否一致
  • 时间戳属性(如 <SourceRevisionId><Version>)是否在构建间变化

GitCommit 自动生成

构建时自动生成 GitCommit.g.cs 文件,包含当前 git 提交哈希:

// $(IntermediateOutputPath)Generated\GitCommit.g.cs
internal static class GitCommit
{
    public const string Hash = "abc1234";
}

实现机制

MSBuild 目标 GenerateGitCommit 在每次构建前运行:

<Target Name="GenerateGitCommit" BeforeTargets="BeforeBuild">
  <Exec Command="git rev-parse --short HEAD"
        ConsoleToMSBuild="true"
        StandardOutputImportance="low"
        IgnoreExitCode="true">
    <Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" />
  </Exec>
  <PropertyGroup>
    <GitCommitHash Condition="'$(GitCommitHash)' == ''">unknown-commit-id</GitCommitHash>
  </PropertyGroup>
  <WriteLinesToFile
    File="$(IntermediateOutputPath)Generated\GitCommit.g.cs"
    Lines="...
      public const string Hash = &quot;$(GitCommitHash)&quot;;..."
    Overwrite="true" />
</Target>
  • 生成的文件位于 $(IntermediateOutputPath)Generated\GitCommit.g.cs(如 obj/Debug/net10.0/Generated/
  • 通过 obj/ 目录的 .gitignore 规则间接排除,不提交到版本控制
  • git 不可用时回退到 "unknown-commit-id"

在代码中的使用

// TelemetryService.cs — 上报时附加提交标识
var commitId = GitCommit.Hash;
// AboutViewModel.cs — 版本号包含提交 ID
Version = $"{VersionInfo.Version}-{VersionInfo.CommitId}";

显示格式示例:1.5.0-abc1234

发布脚本

scripts/build/publish.sh(Linux/macOS)和 scripts/build/publish.ps1(Windows)是多平台发布工具,支持交互式和 CLI 模式。

交互模式

cd scripts/build
./publish.sh   # 启动 TUI 交互界面

# 在交互界面中选择:
# - 发布类型(自包含/框架依赖/全部)
# - 目标平台(Windows x64、Linux x64、macOS x64/arm64)
# - 构建配置(Debug/Release)
# - 可选选项(裁剪、AOT)

CLI 模式

# 语法: publish.sh <mode> <config> [opt] [suffix] [version] [clean] [aot]

# 全平台自包含+框架依赖,裁剪+AOT
./publish.sh both Release opt "" "1.2.1" clean aot

# 仅 Windows x64 自包含发布
./publish.sh full Release "" "" "1.2.1" clean

# 仅框架依赖发布(不包含运行时)
./publish.sh slim Release "" "" "1.2.1"

# 为已有发布文件生成 SHA256 校验表
./publish.sh hash

发布类型

类型 参数 说明
全部(both) both 同时生成自包含和框架依赖两种发布
自包含(full) full 包含 .NET 运行时,无需预装 SDK
框架依赖(slim) slim 不包含运行时,文件更小

发布选项

选项 参数 说明
清理 clean 构建前清理输出目录
AOT aot 使用 Native AOT 预编译(仅自包含)
裁剪 opt 启用 IL 裁剪减小体积(仅自包含)

目标平台

平台 RID 说明
Windows win-x64 输出 .exe + .zip
Linux linux-x64 输出 .tar.gz
macOS Intel osx-x64 输出 .tar.gz
macOS Apple Silicon osx-arm64 输出 .tar.gz

SHA256 校验表

publish.sh hash 扫描 publish/ 目录下所有 SeatFlow-* 文件,输出 Markdown 格式的 SHA256 校验表到标准输出。校验表同时会嵌入 GitHub Release 正文中。

| File | SHA256 |
|------|--------|
| SeatFlow-1.2.1-win-x64.zip | a1b2c3d4... |
| SeatFlow-1.2.1-linux-x64.tar.gz | e5f6g7h8... |
| SeatFlow-1.2.1-osx-arm64.tar.gz | i9j0k1l2... |

清理脚本

scripts/build/clean.shscripts/build/clean.ps1 递归清理所有项目的 bin/obj/ 目录。

cd scripts/build

# 确认后删除
./clean.sh

# 预览模式(dry-run)
./clean.sh -n

# 强制删除(跳过确认)
./clean.sh -f

运行应用

# 开发模式运行
dotnet run --project SeatFlow.Presentation.Avalonia

# 发布后运行(自包含)
./publish/SeatFlow_1.2.1_linux-x64/SeatFlow

WatchdogService

生产运行时,WatchdogService 会监测 UI 线程响应。如果 UI 线程卡顿超过 45 秒,服务会:

  1. 收集进程信息(PID、内存、线程数、句柄数、CPU 时间)、所有线程状态和托管线程池信息
  2. 将诊断信息写入 err_<yyyyMMdd-HHmmss>.log
  3. 尝试弹出错误对话框
  4. 通过 Environment.Exit(1) 强制退出应用

这在开发调试时需要注意——如果断点暂停超过 45 秒,进程会被杀死。

Velopack 打包

SeatFlow 通过 release.py 编排完整的 Velopack 打包流程,包括:

  • 自动更新支持
  • 增量更新(delta updates)
  • 静默安装和卸载
  • 生成 .nupkg + 安装程序 + releases.{channel}.json 更新源

Velopack 深度集成在 Presentation 层:Program.cs 通过 VelopackApp.Build() 注册钩子,UpdateService 使用 UpdateManager 实现自动更新检查和下载,VelopackLocator 用于运行时目录检测。

详见 ADR-010

构建验证清单

每次提交前执行:

# 1. 编译验证
dotnet build

# 2. 全部测试
dotnet test

# 3. 脚本测试
python3 -m pytest scripts/tests/ -v

# 4. i18n 一致性(可选)
python3 scripts/i18n.py check

故障排查

构建失败:Designer.cs 不存在

运行 python3 scripts/i18n.py sync 生成 Resources.Designer.cs

构建失败:Avalonia 编译绑定错误

确保所有 {x:Static} 引用正确,且命名空间声明正确:

xmlns:lang="using:SeatFlow.Presentation.Avalonia.Lang"

发布失败:AOT 不支持某些 API

Native AOT 不支持以下功能:

  • 运行时代码生成
  • 反射(部分支持)
  • System.Reflection.Emit

如果在 AOT 构建中遇到错误,检查代码是否使用了不兼容的 API。

相关文档