BitzOrcas.CodeGeneration.Cli(命令名 bitz-codegen)是唯一承担”业务切片脚手架”职责的生成工具,也是仅有的两个 PackAsTool 打包工具之一。它的生产入口只有一个:--business-slice <schema.json>,从一份严格校验的 JSON 切片定义生成 Contracts、Application、行为测试与裁剪冒烟骨架。
历史的 --inline/--module/--use-case 三种自由输入并没有被删除,但已经降级为审计入口:它们不生成任何 C#,只向 .codegen-output/ 写一份 productionReady=false 的诊断清单并以退出码 2 结束。如果你按老教程敲出的命令得到了 0 个源文件,这不是 bug,是失败关闭在工作。
工具身份与安装
# 商业 Feed 本地安装为 dotnet tool(与 bitz-upgrade 同一发布通道)。dotnet new tool-manifestdotnet tool install BitzOrcas.CodeGeneration.Cli \ --version 1.0.0-alpha1 \ --add-source <commercial-feed>
# 未安装时也可从仓库源码运行。dotnet run --project src/Tooling/BitzOrcas.CodeGeneration.Cli -- --help帮助文本属于模板合同的一部分:verify-template.sh 会断言内部派生选择器不出现在 help 中,回归时以 help 快照为准。
生产入口:business-slice
一条命令的真实效果(schema 取自仓库测试夹具同构的 service-requests.v1.json,输出为真实运行截取):
切片 Schema 固定行业中立形态:一个必填租户的统一聚合加单条 Create 命令,主键由客户端分配 Guid;domainEvents 与 integrationEvents 数组必须显式声明为空。以下是仓库测试夹具同构的法律科技示例:
{ "schemaVersion": 1, "frameworkVersion": "1.0.0-alpha1", "module": { "name": "LegalCases", "baseNamespace": "BitzOrcas.Platform.LegalCases", "description": "民商事案件模块", "code": "legal-cases", "featureCode": "legal-cases.create" }, "aggregate": { "name": "MatterIntake", "pluralName": "MatterIntakes", "description": "租户内待合伙人审批的立案申请", "tableName": "GeneratedMatterIntake", "idType": "guid", "idAllocation": "client", "tenancy": "required", "softDelete": true, "concurrency": true, "fields": [ { "name": "CaseNumber", "description": "法院或仲裁案件编号", "type": "string", "required": true, "maxLength": 64, "normalize": "trim", "errorMember": "MatterIntakeInvalidCaseNumber", "errorCode": "LegalCases.MatterIntake.InvalidCaseNumber" }, { "name": "DisputeAmount", "description": "争议标的金额", "type": "decimal", "required": false, "minimum": 0, "maximum": 100000000000, "normalize": "none", "errorMember": "MatterIntakeInvalidDisputeAmount", "errorCode": "LegalCases.MatterIntake.InvalidDisputeAmount" } ] }, "create": { "commandName": "SubmitMatterIntakeCommand", "description": "在当前租户内提交立案申请", "route": "/api/matter-intakes", "resourceType": "matter-intake", "permissionMember": "SubmitMatterIntake", "permissionCode": "legal-cases.matter-intake.create", "tenantErrorMember": "TenantRequired", "tenantErrorCode": "LegalCases.Tenant.Required" }, "domainEvents": [], "integrationEvents": []}每个字段的 errorMember/errorCode 强制成对出现——生成的校验规则直接携带强类型错误码,防止”裸字符串返回”。调用方式:
dotnet bitz-codegen --business-slice ./design/matter-intakes.v1.json \ --output .codegen-output目标目录已存在会直接拒绝覆盖;没有 OverwriteStrategy 可配。想要重新生成,先清掉上一次产物并核对差异。
Manifest 与证据字段
一次成功生成结束时 manifest 记录的不只是文件清单:
| 字段 | 含义 |
|---|---|
Status | ready 或 blocked;blocked 不是失败,而是带诊断的可审阅结果 |
ProductionReady | 生产可用标记;审计入口恒为 false |
SchemaSha256 | 输入切片的哈希,锁定”这次生成对应哪份定义” |
SourceGeneratorOwned | 归源生成器拥有的接线清单:dependency-injection、endpoint、orm-fluent-configuration、module-catalog |
ExplicitlyUnsupported | v1 明确不支持的形态:update-command、query、domain-event、integration-event |
SourceGeneratorOwned 解释了为什么生成物里看不到 DI 注册和 Endpoint 文件——那些由 Roslyn 源生成器在编译期接管,手写只会引入第二份事实。写入采取两阶段:临时目录整体写完后 Directory.Move 原子落位,IO 失败时删除临时目录并报 BOCG310,目标目录保持字节不变。
审计入口:失败关闭的旧形态
三种历史输入仍然可用,但角色变了:
# 这是合法命令吗?不是生产路径:它会写审计清单然后退出 2。dotnet bitz-codegen --inline \ --module-name Tracker \ --aggregate MatterIntake \ --property 'CaseNumber:string:64' \ --property 'DisputeAmount:decimal'echo $? # 2;.codegen-output 里只有 manifest,没有任何 C#| 旧入口 | 当前行为 |
|---|---|
--module <json>(聚合模式) | 写 productionReady=false 诊断清单,退出 2 |
--inline --module-name … --aggregate … | 同上 |
--module … --use-case …(用例模式) | 同上 |
--with-endpoint | 明确拒绝,不再生成手写端点 |
--dry-run / --no-staging | 所有入口均拒绝;工具绝不直写源码树 |
这些入口的存在价值是让历史脚本、课件和老 README 得到确定性的”已被时代淘汰”反馈,而不是悄悄产出不符合当前架构的半成品。
错误码族
| 族 | 语义 | 共同点 |
|---|---|---|
BOCG1xx / BOCG2xx | 旧输入审计(如上文三个入口) | 零 C# 输出 |
BOCG3xx | 生产 schema 校验失败 | 零写入 |
自动化判断只用两个信号:进程退出码与 manifest 的 ProductionReady 字段;不要解析人类可读文案。
人工落地流程
- 在设计评审中确认业务键、权限码(
{module}.{resource}.{action})、错误码归属后再写 schema——schema 即契约,进入SchemaSha256证据链。 - 运行生成,检查目标目录与 manifest 的
ready/ProductionReady=true。 - 把生成项目接入 Consumer Solution:加入
.slnx,由 owner 目录的[AppModule]标记与DependsOn收编治理关系。 - 为行为测试补真实 fixture 与断言;切片自带 trim smoke,确认它在 CI 的裁剪矩阵中执行。
- 补齐 XML 注释与数据范围规则后,运行 Application、Architecture 与 Integration 门禁。
- 删除
.codegen-output暂存副本;生成目录即唯一事实。
验证命令
# 生成器模板、原子落位与 manifest 合同。dotnet test tests/BitzOrcas.CodeGeneration.Tests --configuration Release
# 生成器作为包被隔离项目消费的合同。dotnet test tests/BitzOrcas.Generator.Package.Tests --configuration Releasetests/BitzOrcas.CodeGeneration.Tests/Fixtures/service-requests.v1.json 是官方夹具:本页示例的字段结构与其逐一对应。遇到 schema 行为不确定时以该夹具和它的断言为准,不要靠猜。
常见错误
- 把旧教程里的
--inline流程当生产路径,拿到退出码 2 才发现世界变了; - 目标目录残留上次生成物导致整体拒绝;
- 期待生成器产出 update/query 或领域事件——
ExplicitlyUnsupported白纸黑字写着不支持; - 事件数组省略而不是显式置空;
- 把
blocked清单当失败静默重跑,而不读诊断定位 schema 问题。