bitz-upgrade 规划、应用并安全回滚 Consumer Solution 中受管的 BitzOrcas 包版本升级。它是一个可打包 dotnet tool(BitzOrcas.Upgrade.Cli),含三个子命令:plan、apply、rollback。它只修改 Directory.Packages.props 中既有 BitzOrcas.* PackageVersion 条目的 Version 属性——绝不触碰业务源码、csproj、配置、清单或数据库。
它动什么
写入面刻意很窄。CentralPackageVersionEditor 仅替换 <PackageVersion Include="BitzOrcas.…"> 节点的 Version 值,字节结构、注释与第三方包保持原样。包版本以外的一切——破坏性变更、配置差异、数据库迁移、模板持有的 Host 外壳——只作为手工步骤出现在 plan 中;不可逆影响会阻断 apply。
四个版本面
一次 BitzOrcas 发布携带四个必须同步移动的版本面:
| 版本面 | 内容 |
|---|---|
| 模板 | Consumer Solution 脚手架 |
| SDK / BOM | 中央 Directory.Packages.props 版本 |
| 商业包 | 私有 Feed 上的 NuGet 包版本 |
| 许可协议 | Runtime License 的 versionRange |
一个 release train 使用统一产品版本。升级 map(template-upgrade-map.json,managedFiles 约束为 ["Directory.Packages.props"],packageGraphPolicy: "unchanged")是工具读取的机器可读源。
命令
# Plan:计算确定性 plan,不写入。输出到 stdout,# 或用 --output 写到 Consumer 工作树外供审阅。bitz-upgrade plan --root <consumer> --map <upgrade-map.json> --to <version> [--output <plan.json>]
# Apply:修改 Directory.Packages.props 并记录审计状态。# 带 --plan 时,外部审阅过的 plan 必须与重算 plan 字节匹配。bitz-upgrade apply --root <consumer> --map <upgrade-map.json> --to <version> [--plan <plan.json>]
# Rollback:从记录的状态恢复上一包版本。bitz-upgrade rollback --root <consumer>| 选项 | 适用 | 必填 | 语义 |
|---|---|---|---|
--root | 全部 | 是 | Consumer 工作树根 |
--map | plan、apply | 是 | 升级 map 路径 |
--to | plan、apply | 是 | 目标版本(须等于 map 版本或已在该版本) |
--output | plan | 否 | plan 文件,须在 Consumer 工作树外 |
--plan | apply | 否 | 外部审阅过的 plan(须字节匹配) |
审计轨迹与完整性
每次 apply 在 .bitzorcas/ 下写不可变审计轨迹:
upgrade-state.json+upgrade-state.sha256—— 活动状态(from/to 版本、受管文件/manifest/map/包图/plan/备份的校验和、时间戳)upgrade-backups/{from}-to-{to}/Directory.Packages.props.bak—— apply 前备份- 回滚时:状态移入
upgrade-history/{from}-to-{to}.applied.json(+.sha256),并写last-rollback.json
每个状态转换都校验和(64 字符小写 hex)且失败关闭:孤立校验和、缺失校验和、校验和不匹配、错误 schema 版本、已存在备份/状态、.bitzorcas 为重解析点等,各产生独立 BITZUPnnn 错误并中止。回滚在恢复前重新校验当前包校验和、manifest 校验和、包图校验和与备份校验和;任一不匹配则中止并保留 apply 时字节。
不可逆门禁
若升级 map 声明了不可逆迁移或配置变更(canApply=false),apply 被阻断——工具只报告手工步骤。工具绝不在不可逆迁移上伪造自动回滚。回滚不是 git checkout:它从 .bitzorcas/ 状态恢复记录的包版本,并由校验和验证。
退出码
| 码 | 含义 |
|---|---|
0 | 成功 |
2 | 用法错误 |
3 | 输入 / schema 无效 |
4 | 不兼容(未知目标、不支持的源、无直连路径) |
5 | dirty / drift(磁盘状态与重算结果不同) |
6 | I/O 失败 |
130 | 取消 |
错误以固定格式 BITZUPnnn: message 写 stderr;stdout 只承载 plan 或成功状态。
受审 plan 的最小流程
把 plan 写到 Consumer 工作树之外,并在审批后把同一份文件交给 apply。工具会重算 plan 并做字节比较,因此源码、map 或包图在审批后变化都会阻断写入:
# 临时目录必须位于 Consumer 工作树外。UPGRADE_REVIEW_DIR="$(mktemp -d)"bitz-upgrade plan --root ./consumer --map ./template-upgrade-map.json \ --to 1.2.0 --output "$UPGRADE_REVIEW_DIR/plan.json"
# 审批通过后应用原文件,并验证锁定还原与测试。bitz-upgrade apply --root ./consumer --map ./template-upgrade-map.json \ --to 1.2.0 --plan "$UPGRADE_REVIEW_DIR/plan.json"dotnet restore ./consumer --locked-modedotnet test ./consumer --no-restore执行完要把 plan、工具版本、upgrade map 哈希、Directory.Packages.props diff 和验证结果放进同一个变更记录。临时目录中的 plan 不是 Secret,但可能暴露包图和升级步骤,应按内部构建元数据管理。