优化
This commit is contained in:
@@ -2,6 +2,64 @@
|
||||
|
||||
全量验收只认测试环境 HTTP 脚本。它们通过 Gateway 调用已部署服务,按业务模块执行真实登录、权限、状态、幂等、跨服务和数据链路检查;脚本通过后,剩余工作是 Admin/Client 的真实接口调用与浏览器样式验收,以及 PDA 页面/设备验收。
|
||||
|
||||
## 脚本目录归属
|
||||
|
||||
脚本按作用域放置,不要求全部集中到根 `scripts/`:
|
||||
|
||||
| 目录 | 归属 | 是否直接运行 |
|
||||
|---|---|---|
|
||||
| `scripts/` | 仓库级验收、回归、诊断、环境辅助和静态合同 | 本文“仓库级入口清单”列出的文件可以直接运行 |
|
||||
| `scripts/admin-test-env-modules/` | `admin-test-env-acceptance.mjs` 动态加载的业务模块、fixture 和离线合同 | 业务 `.mjs` 原则上不直接运行;模块名、依赖和边界见该目录 `README.md` |
|
||||
| `scripts/openapi-validation/` | 全仓 OpenAPI 发现、解析和引用校验 | 从该目录安装依赖后运行 `validate-openapi.mjs`;`validate-openapi.test.mjs` 是离线合同 |
|
||||
| `firstleg/scripts/` | Firstleg 服务内部 Java 包依赖分析 | 只维护 Firstleg 内部模块化基线,与服务一起演进 |
|
||||
| `lastleg-service/scripts/` | Lastleg 服务内部 Java 包依赖分析 | 只维护 Lastleg 内部模块化基线,与服务一起演进 |
|
||||
| `warehouse/scripts/` | Warehouse 公共主数据等服务局部离线合同 | 从后端根用 Node test runner 执行,不连接数据库 |
|
||||
| `deploy/scripts/` | Jenkins/部署主流程调用的镜像部署与测试库初始化脚本 | 只在受控部署或测试基础设施流程运行 |
|
||||
| `deploy/rocketmq/` | RocketMQ 容器启动时渲染 broker 配置 | 由容器入口调用,不作为人工验收入口 |
|
||||
|
||||
因此 `firstleg/scripts/`、`lastleg-service/scripts/` 和 `deploy/**` 不是散落或放错目录;它们靠近所属部署单元或运行组件。仓库检索到的可执行脚本如果既不在上述目录,也没有在本表登记,应视为脚本归属缺失。
|
||||
|
||||
## 仓库级入口清单
|
||||
|
||||
下表覆盖 `scripts/` 下所有非 `*.test.mjs` 的可执行入口。`*.test.mjs` 统一为离线 Node 静态合同,不访问测试环境;`admin-test-env-modules/*.mjs` 的逐模块说明由该目录 `README.md` 和总入口注册表维护。
|
||||
|
||||
| 分类 | 入口 | 用途与副作用 |
|
||||
|---|---|---|
|
||||
| 测试环境 HTTP | `admin-test-env-acceptance.mjs` | Admin 全模块真实 HTTP 验收;按模块创建、更新、停用测试数据 |
|
||||
| 测试环境 HTTP | `client-test-env-acceptance.mjs` | Client 完整真实 HTTP 链路;写入客户、订单、入库、权限和消息数据 |
|
||||
| 测试环境 HTTP | `client-phase2-test-env-acceptance.mjs` | Client 二期入库、测量、费用和权限专项;写测试数据 |
|
||||
| 测试环境 HTTP | `create-pending-review-orders.mjs` | 固定客户批量创建并提交待审核订单,不做平台审核和后续履约 |
|
||||
| 测试环境 HTTP | `it-test-wait-split-bulk.mjs` | 固定“IT测试”与“义乌仓”,渠道等随机,逐票推进到 `WAIT_SPLIT`;失败继续并落报告。只复用 `TP-001`/`YW-TP-002`,不新增托盘或库位,库位不足使用公共位 `A0` |
|
||||
| 测试环境 HTTP | `dimension-ocr-pricing-test-env.ps1` | 尺寸、OCR 和渠道计价专项,上传本地图片并写测试业务数据;包含历史默认参数,只能显式传入当前目标参数后使用 |
|
||||
| 测试环境 HTTP | `export-center-test-env-acceptance.ps1` | 导出中心测试环境验收,会创建导出任务和相关测试数据 |
|
||||
| 测试环境 HTTP | `phase2-test-env-acceptance.ps1` | 二期测试环境 API 验收,会写业务数据 |
|
||||
| 场景组件 | `mojia-measurement-scenario.mjs` | 被 Admin 验收入口复用的墨家测量场景;不是独立 CLI,调用正式测量接口并上传图片 |
|
||||
| 定向诊断 | `pda-final-complete-diagnostic.mjs` | 对指定 PDA task 回查最终完成门禁;传 `--seed-evidence` 时会补五类证据并产生写操作 |
|
||||
| 本地真实 API | `order-warehouse-real-api-regression.ps1` | 本地 Order/Warehouse 往来单位真实 API 回归,并直接读写本机 MySQL;不得指向共享或测试数据库 |
|
||||
| 一期本地验收 | `phase1-acceptance.ps1` | 一期本地服务/API 综合验收,会创建本地业务数据 |
|
||||
| 一期本地验收 | `phase1-business-maturity-regression.ps1` | 一期业务成熟度回归,调用本地服务并生成报告 |
|
||||
| 一期本地验收 | `phase1-onboarding-order-e2e.ps1` | 注册、资质、审核到下单的本地 E2E,会创建客户、仓库、往来单位和订单 |
|
||||
| 本地质量 | `backend-full-regression.ps1` | Mapper 门禁后执行受影响后端 Maven 测试;`-DryRun` 只打印与校验 |
|
||||
| 本地质量 | `frontend-full-regression.ps1` | 编排 Admin/Client 本地测试与类型检查,不访问 Gateway |
|
||||
| 本地质量 | `database-comment-audit.ps1` | 离线扫描数据库中文注释,不连接数据库 |
|
||||
| 本地质量 | `local-db-full-acceptance.ps1` | 只允许本机 MySQL 的受控 SQL 验收;非 dry-run 会写本地测试库 |
|
||||
| 本地质量 | `mapper-scan-contract.mjs` | 离线检查 Mapper 注解与扫描入口,不启动 Spring、不连接数据库 |
|
||||
| 本地质量 | `java-quality-summary.mjs` | 聚合 Maven 拓扑、OpenAPI、JaCoCo 和 SpotBugs 已有报告,不启动服务 |
|
||||
| 本地质量 | `agents-index-contract.ps1` | 离线检查 AGENTS 快速索引与关键入口一致性 |
|
||||
| 契约数据 | `synchronous-dependency-baseline.mjs` | 同步服务依赖合同的数据源,只由相邻合同测试导入,不是 CLI |
|
||||
| OpenAPI | `openapi-validation/validate-openapi.mjs` | 发现并解析各服务 OpenAPI,检查跨文件引用;只读源码 |
|
||||
| 本地环境 | `local-env.ps1` | 本地开发环境公共参数/辅助函数,由其他 PowerShell 脚本加载 |
|
||||
| 本地环境 | `publish-local-nacos-config.ps1` | 将 `config/nacos/local/*.yml` 发布到指定本地 Nacos,会修改 Nacos 配置 |
|
||||
| 密钥配置 | `generate-overseas-jwk.mjs` | 生成 3072 位海外 JWT RSA JWK 并写入指定 `deploy/env/.env.*`;已有 JWK 时拒绝覆盖,密钥文件不得提交 |
|
||||
| 迁移辅助 | `migrate-local-qualification-file.ps1` | 本地资质文件迁移辅助,会修改本地文件/数据;运行前核对脚本参数和备份策略 |
|
||||
| Jenkins 管理 | `provision-development-service-jobs.groovy` | Jenkins Script Console 批量准备开发服务 Job;默认 `applyChanges=false` 仅预览,改为 true 会创建 Job |
|
||||
|
||||
部署目录的入口另有:`deploy/scripts/deploy-built-service.sh`(单服务健康检查与失败回滚)、`deploy/scripts/deploy-development-service.sh`(经 SSH 部署开发服务)、`deploy/scripts/deploy-services.sh`(按服务列表编排部署)、`deploy/scripts/initialize-test-databases.sh`(初始化测试基础设施数据库)和 `deploy/rocketmq/render-broker-config.sh`(容器内渲染并启动 RocketMQ broker)。这些脚本都会改变运行环境,不能作为普通本地检查执行。
|
||||
|
||||
服务局部分析入口为 `firstleg/scripts/analyze-firstleg-dependencies.mjs` 与 `lastleg-service/scripts/analyze-lastleg-dependencies.mjs`,相邻的 `*.test.mjs` 负责对基线和违规依赖做离线回归;`warehouse/scripts/warehouse-public-master-data-contract.test.mjs` 只读校验 Warehouse 公共主数据 CSV 与 SQL。SQL 辅助文件 `scripts/db/incremental.sql` 不是当前统一部署入口,正式数据库变更以 `deploy/sql/README.md` 指向的统一增量为准。
|
||||
|
||||
新增可直接运行的脚本时,必须同时在本节登记用途、目标环境、是否写数据和密钥边界,并运行 `node --test scripts/script-documentation-contract.test.mjs`。仅新增 `*.test.mjs` 或 `admin-test-env-modules/` 内部模块时,分别更新对应合同范围或模块 README,不把内部文件误写成独立入口。
|
||||
|
||||
| 验收目标 | 唯一入口 | 数据副作用 | 覆盖范围 |
|
||||
|---|---|---|---|
|
||||
| 平台后台全模块 HTTP 验收 | `scripts/admin-test-env-acceptance.mjs` | 会创建、更新或最终停用测试数据 | `--modules` 默认列表中的平台客户、仓储、订单、入库、分柜、装柜、船期、拖车、报关、财务、通知、统计等模块 |
|
||||
|
||||
@@ -42,9 +42,10 @@
|
||||
- SKU 数随机为 `1–4`,但不得超过本票总箱数。
|
||||
- 总箱数随机拆分到各 SKU,每个 SKU 至少 1 箱。
|
||||
- 毛重、净重、数量、申报价值和体积根据各 SKU 箱数计算。
|
||||
- 称重图片、托盘和占用库位数量必须与上述托数完全一致。
|
||||
- 称重图片数量与上述托数一致;每托只在既有 `TP-001`、`YW-TP-002` 中随机复用一个托盘编码,不创建新的托盘主档,因此同一票和不同票都允许重复使用这两个编码。
|
||||
- 库位由正式仓储预占/结算接口分配,不创建库位主档;普通库位不足时直接使用仓库公共位 `A0`。托盘复用不改变 `palletCount = ceil(totalPackageCount / 30)` 的业务托数。
|
||||
- 箱唛打印冻结真实总箱数;多 SKU 测量使用各 SKU 实际箱数和对应箱序号。
|
||||
- 通过正式文件、称重 OCR、托盘库位、测量提交和审核接口推进状态,不直接写数据库。
|
||||
- 通过正式文件、称重 OCR、托盘库位预占、测量提交和审核接口推进状态,不直接写数据库。
|
||||
|
||||
## 尽力执行语义
|
||||
|
||||
@@ -92,5 +93,6 @@ node scripts/it-test-wait-split-bulk.mjs `
|
||||
- 仅用于已明确授权的测试环境,禁止用于生产环境。
|
||||
- 账号、密码、Token 和环境地址只从本机环境配置加载,不进入源码或报告。
|
||||
- 不自动删除已成功或部分成功的数据。
|
||||
- 不新增托盘或库位主档;只能复用 `TP-001`、`YW-TP-002`,库位不足落公共位 `A0`。
|
||||
- 不重置数据库、不执行 SQL、不绕过正式状态机。
|
||||
- 清理测试数据或文件必须另行获得明确授权。
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
需要为人工联调批量准备同一客户、同一国内仓和同一渠道的 `WAIT_SPLIT` 数据时,使用[《批量待分柜数据生成指南》](批量待分柜数据生成指南.md)。该入口通过正式下单、入库、称重和测量接口生成数据,支持 FBA、海外仓、私人地址及一件代发等稳定随机组合;不得直接写库或用于生产环境。
|
||||
|
||||
固定“IT测试”客户与“义乌仓”、其余线路随机并尽力生成最多 8,000 票时,独立编排入口是 `../it-test-wait-split-bulk.mjs`。它仍复用本目录的 `orders.mjs` 与 `inbound-measurement.mjs`,但逐票保存日志且单票失败后继续。测量前置只随机复用既有 `TP-001`、`YW-TP-002`,不得调用托盘新增接口;库位由正式仓储接口分配,普通位不足时使用公共位 `A0`,不得调用库位新增接口。
|
||||
|
||||
订单造数中的 `GET /api/merchant/v1/partners/candidates?type=SHIPPER` 属于 Warehouse 正式客户候选能力。失败时订单脚本仍可使用 sender 快照继续收集后续链路证据,但 HTTP 503/`S0503` 必须保留为 deployment blocker,不能因订单、测量、分柜或装柜后续通过而降级为 coverage gap。
|
||||
|
||||
人工分柜采用两个可选模块,不进入默认全量入口:`manual-order-splitting-fixture.mjs` 基于本轮至少四票 `WAIT_SPLIT` 数据生成部分分配、整票拼柜和未分配对照清单;人工在 Admin 完成计划分配后,`manual-order-splitting-verify.mjs` 读取准备报告和 `loadingPlanId`,只读核对柜次范围、计划箱数及候选余量。完整命令见同一指南的“人工分柜验收”章节。
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
- 固定渠道存在当前 `ACTIVE` 价格簿和进仓码前缀。
|
||||
- FBA/OVERSEAS 至少存在一个与固定渠道价格明细匹配的目的仓。
|
||||
- File、Order、Firstleg、Warehouse、IAM、Auth 等链路可用。
|
||||
- 测量托盘只复用仓库已有 `TP-001`、`YW-TP-002`;脚本不创建托盘主档。库位由正式仓储接口分配,普通位不足时使用公共位 `A0`,脚本不创建库位主档。
|
||||
|
||||
账号、密码、环境域名和 Token 不得写入本文、源码、提交记录或报告。建议由本地未提交环境文件或当前终端环境变量提供。
|
||||
|
||||
@@ -405,7 +406,7 @@ node scripts/admin-test-env-acceptance.mjs `
|
||||
|
||||
## 失败、重跑与批量拆分
|
||||
|
||||
- 批次遇到第一条失败即停止,已经成功创建的订单不会自动删除或回滚。
|
||||
- `admin-test-env-acceptance.mjs --wait-split-count` 的普通批次遇到第一条失败即停止;`it-test-wait-split-bulk.mjs` 会记录该票失败并继续尝试后续票。两种入口都不会自动删除或回滚已经成功创建的订单。
|
||||
- 先查看日志和 JSON 报告中最后一个成功 fixture、失败接口的 `code/requestId/traceId`,修复前置后再运行剩余数量。
|
||||
- 重跑会生成新业务单号和入仓码,不覆盖旧订单;不要假设跨多次运行的入仓码一定连续。
|
||||
- 每次运行的随机序列从 1 重新开始;分批执行时组合可能重复,但仍保持固定三项和真实契约。
|
||||
@@ -429,6 +430,7 @@ node scripts/admin-test-env-acceptance.mjs `
|
||||
|
||||
```powershell
|
||||
node --check scripts/admin-test-env-acceptance.mjs
|
||||
node --check scripts/it-test-wait-split-bulk.mjs
|
||||
node --check scripts/admin-test-env-modules/orders.mjs
|
||||
node --check scripts/admin-test-env-modules/manual-order-splitting-fixture.mjs
|
||||
node --check scripts/admin-test-env-modules/manual-order-splitting-verify.mjs
|
||||
@@ -440,7 +442,7 @@ node --check scripts/admin-test-env-modules/manual-pda-batch-fixture.mjs
|
||||
node --check scripts/admin-test-env-modules/manual-pda-batch-verify.mjs
|
||||
node --check scripts/admin-test-env-modules/manual-loading-complete-fixture.mjs
|
||||
node --check scripts/admin-test-env-modules/manual-loading-complete-verify.mjs
|
||||
node --test scripts/admin-test-env-modules/merchant-qualification-fixture-contract.test.mjs scripts/admin-test-env-modules/inbound-measurement-box-code-contract.test.mjs scripts/admin-test-env-modules/manual-order-splitting-contract.test.mjs scripts/admin-test-env-modules/manual-preload-push-contract.test.mjs scripts/admin-test-env-modules/manual-pda-ready-contract.test.mjs scripts/admin-test-env-modules/manual-pda-batch-contract.test.mjs scripts/admin-test-env-modules/manual-loading-complete-contract.test.mjs
|
||||
node --test scripts/script-documentation-contract.test.mjs scripts/admin-test-env-modules/it-test-wait-split-bulk-contract.test.mjs scripts/admin-test-env-modules/merchant-qualification-fixture-contract.test.mjs scripts/admin-test-env-modules/inbound-measurement-box-code-contract.test.mjs scripts/admin-test-env-modules/manual-order-splitting-contract.test.mjs scripts/admin-test-env-modules/manual-preload-push-contract.test.mjs scripts/admin-test-env-modules/manual-pda-ready-contract.test.mjs scripts/admin-test-env-modules/manual-pda-batch-contract.test.mjs scripts/admin-test-env-modules/manual-loading-complete-contract.test.mjs
|
||||
git diff --check
|
||||
```
|
||||
|
||||
|
||||
@@ -107,6 +107,14 @@ Assert-Contains $backendAgents '所有生产 MyBatis Mapper 接口必须显式
|
||||
Assert-Contains $backendAgents 'Mapper 新增、移动、Bean 缺失与扫描遗漏' '后端 Mapper 快速路由'
|
||||
Assert-Contains $mapperScanContract 'annotationClass = Mapper.class' 'Mapper 根包注解过滤合同'
|
||||
Assert-Contains $mapperScanContract '禁止分散维护 MapperScan' 'Mapper 单一扫描入口合同'
|
||||
$firstlegAgents = Read-RequiredText (Join-Path $backendRoot 'firstleg/AGENTS.md')
|
||||
$coloadOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/coload-groups-v1.yaml')
|
||||
Assert-Contains $rootAgents 'modules/unified-orders/api/coLoadGroups.ts' '根同柜不可拆组入口'
|
||||
Assert-Contains $adminAgents '成员数是入仓片段数,不等于订单票数' 'Admin 同柜成员语义'
|
||||
Assert-Contains $backendAgents 'loading/coload/controller/PlatformColoadGroupController.java' '后端同柜不可拆组入口'
|
||||
Assert-Contains $firstlegAgents '服务端冻结每票全部 `WAIT_SPLIT` 可用入仓片段与满箱数' 'Firstleg 同柜建组边界'
|
||||
Assert-Contains $coloadOpenApi '允许跨客户及不同目的仓港成组,仅要求国内仓和渠道一致' '同柜资格 OpenAPI'
|
||||
Assert-Contains $coloadOpenApi '服务端解析每个订单全部 WAIT_SPLIT' '同柜订单展开 OpenAPI'
|
||||
$mapperModuleAgents = @(
|
||||
@{ Module = 'audit-service'; Application = 'BaiyueAuditApplication.java' },
|
||||
@{ Module = 'auth'; Application = 'BaiyueAuthApplication.java' },
|
||||
@@ -408,6 +416,8 @@ $criticalPaths = @(
|
||||
'apps/admin-web/src/modules/container-loading/api/platformContainerCustoms.ts',
|
||||
'apps/admin-web/src/modules/container-loading/api/platformContainerCustoms.test.ts',
|
||||
'apps/admin-web/src/modules/container-loading/api/platformContainerLoading.ts',
|
||||
'apps/admin-web/src/modules/unified-orders/api/coLoadGroups.ts',
|
||||
'apps/admin-web/src/modules/unified-orders/pages/UnifiedOrdersView.vue',
|
||||
'apps/admin-web/src/modules/ocean-bookings/api/platformOceanBookings.ts',
|
||||
'apps/admin-web/src/modules/ocean-bookings/pages/OceanBookingsView.vue',
|
||||
'apps/admin-web/src/core/routing/navigationRecovery.ts',
|
||||
@@ -483,6 +493,9 @@ $criticalPaths = @(
|
||||
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/customs/container/controller/MerchantContainerCustomsController.java',
|
||||
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/customs/container/service/ContainerCustomsService.java',
|
||||
'baiyue-firstleg/firstleg/src/main/resources/openapi/customs-v1.yaml',
|
||||
'baiyue-firstleg/firstleg/src/main/resources/openapi/coload-groups-v1.yaml',
|
||||
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/loading/coload/controller/PlatformColoadGroupController.java',
|
||||
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/loading/coload/service/ColoadGroupService.java',
|
||||
'baiyue-firstleg/file/src/main/resources/openapi/customs-file-and-export-v1.yaml',
|
||||
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/outbound/dispatch/controller/PlatformOutboundDispatchController.java',
|
||||
'baiyue-firstleg/firstleg/src/main/resources/openapi/phase3-container-overview-v1.yaml',
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* 为已授权的非生产环境尽力生成 IT测试/义乌仓 WAIT_SPLIT 数据。
|
||||
*
|
||||
* 每票随机 1-300 箱(可通过参数缩小),失败会记录后继续;不会自动清理已写入数据。
|
||||
* 测量前置只复用 TP-001/YW-TP-002,不创建托盘;库位由正式仓储接口分配,
|
||||
* 普通位不足时由服务端落公共位 A0,脚本不创建库位。
|
||||
* 账号、密码和 Gateway 只从 admin-test-env-acceptance.mjs 支持的环境变量读取。
|
||||
*/
|
||||
import { randomInt } from 'node:crypto'
|
||||
import { appendFile, mkdir, writeFile } from 'node:fs/promises'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readdir, readFile } from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import test from 'node:test'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const repositoryRoot = path.resolve(fileURLToPath(new URL('..', import.meta.url)))
|
||||
const scriptsReadme = path.join(repositoryRoot, 'scripts', 'README.md')
|
||||
const excludedDirectoryNames = new Set([
|
||||
'.git', '.logs', 'dist', 'node_modules', 'output', 'outputs', 'reports', 'target', 'uni_modules',
|
||||
])
|
||||
const allowedDirectoryPrefixes = [
|
||||
'scripts/',
|
||||
'deploy/scripts/',
|
||||
'deploy/rocketmq/',
|
||||
'firstleg/scripts/',
|
||||
'lastleg-service/scripts/',
|
||||
'warehouse/scripts/',
|
||||
]
|
||||
|
||||
async function executableFiles(directory, extensions, { excludeTests = true } = {}) {
|
||||
const entries = await readdir(path.join(repositoryRoot, directory), { withFileTypes: true })
|
||||
return entries
|
||||
.filter((entry) => entry.isFile())
|
||||
.filter((entry) => extensions.some((extension) => entry.name.endsWith(extension)))
|
||||
.filter((entry) => !excludeTests || !entry.name.endsWith('.test.mjs'))
|
||||
.map((entry) => `${directory}/${entry.name}`.replaceAll('\\', '/'))
|
||||
}
|
||||
|
||||
async function discoverScriptFiles(directory = repositoryRoot) {
|
||||
const discovered = []
|
||||
const entries = await readdir(directory, { withFileTypes: true })
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory() && (
|
||||
excludedDirectoryNames.has(entry.name)
|
||||
|| entry.name.startsWith('node_modules.')
|
||||
|| entry.name.startsWith('.codex-')
|
||||
|| entry.name.startsWith('.runtime-')
|
||||
)) continue
|
||||
const absolute = path.join(directory, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
discovered.push(...await discoverScriptFiles(absolute))
|
||||
continue
|
||||
}
|
||||
if (!['.mjs', '.ps1', '.sh', '.groovy'].some((extension) => entry.name.endsWith(extension))) continue
|
||||
discovered.push(path.relative(repositoryRoot, absolute).replaceAll('\\', '/'))
|
||||
}
|
||||
return discovered
|
||||
}
|
||||
|
||||
test('executable scripts only live in documented directories', async () => {
|
||||
const files = await discoverScriptFiles()
|
||||
const misplaced = files.filter((file) => !allowedDirectoryPrefixes.some((prefix) => file.startsWith(prefix)))
|
||||
assert.deepEqual(misplaced, [], `以下脚本位于未登记目录:\n${misplaced.join('\n')}`)
|
||||
})
|
||||
|
||||
test('all directly runnable scripts are documented in scripts/README.md', async () => {
|
||||
const readme = await readFile(scriptsReadme, 'utf8')
|
||||
const files = [
|
||||
...await executableFiles('scripts', ['.mjs', '.ps1', '.groovy']),
|
||||
...await executableFiles('scripts/openapi-validation', ['.mjs']),
|
||||
...await executableFiles('deploy/scripts', ['.sh']),
|
||||
...await executableFiles('deploy/rocketmq', ['.sh']),
|
||||
...await executableFiles('firstleg/scripts', ['.mjs']),
|
||||
...await executableFiles('lastleg-service/scripts', ['.mjs']),
|
||||
]
|
||||
|
||||
const undocumented = files.filter((file) => {
|
||||
const relativeToScripts = file.startsWith('scripts/') ? file.slice('scripts/'.length) : file
|
||||
return !readme.includes(file) && !readme.includes(relativeToScripts)
|
||||
})
|
||||
|
||||
assert.deepEqual(undocumented, [], `以下可执行脚本未登记用途与边界:\n${undocumented.join('\n')}`)
|
||||
})
|
||||
|
||||
test('README explains internal modules and test scripts are not standalone entries', async () => {
|
||||
const readme = await readFile(scriptsReadme, 'utf8')
|
||||
assert.match(readme, /\*\.test\.mjs.*离线 Node 静态合同/)
|
||||
assert.match(readme, /admin-test-env-modules\/\*\.mjs.*逐模块说明/)
|
||||
assert.match(readme, /warehouse\/scripts\/warehouse-public-master-data-contract\.test\.mjs/)
|
||||
})
|
||||
Reference in New Issue
Block a user