import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' test('生产发布面透传免登配置并保留已有项目 login', () => { const compose = readFileSync('docker-compose.yml', 'utf8') const example = readFileSync('.env.example', 'utf8') const deploy = readFileSync('scripts/deploy-material-host.sh', 'utf8') const gitDeploy = readFileSync('scripts/git-build-deploy.ps1', 'utf8') const testRunner = readFileSync('scripts/run-tests.mjs', 'utf8') const packageJson = JSON.parse(readFileSync('package.json', 'utf8')) const dockerfile = readFileSync('Dockerfile', 'utf8') assert.match(dockerfile, /^ARG BASE_IMAGE=node:22\.23\.4-alpine@sha256:[a-f0-9]{64}$/m) assert.match(gitDeploy, /s\/\^ARG BASE_IMAGE=\/\/p/) assert.match(gitDeploy, /build_args=\(--build-arg "VCS_REF=\$commit_sha"\)/) assert.doesNotMatch(gitDeploy, /--build-arg "BASE_IMAGE=/) for (const key of [ 'DINGTALK_CORP_ID', 'YYD_NOTIFICATION_PUBLIC_BASE_URL', 'DINGTALK_LOGIN_TICKET_TTL_SECONDS', 'WORKER_SEND_MIN_INTERVAL_MS', ]) { assert.match(compose, new RegExp(key)) assert.match(example, new RegExp(key)) assert.match(deploy, new RegExp(key)) } assert.match(compose, /YYD_NOTIFICATION_DIRECTORY_URL/) assert.match(example, /YYD_NOTIFICATION_DIRECTORY_URL/) assert.match(deploy, /YYD_NOTIFICATION_DIRECTORY_URL/) assert.match(gitDeploy, /YYD_NOTIFICATION_DIRECTORY_URL/) assert.match(gitDeploy, /for line in compose_required:/) assert.match(gitDeploy, /compose_changed = True/) assert.doesNotMatch(gitDeploy, /any\(present\) and not all\(present\)/) assert.match(deploy, /old_login = by_code\.get\(code, \{\}\)\.get\('login'\)/) assert.match(deploy, /def project_with_preserved_login/) assert.match(deploy, /project\['login'\] = login/) assert.match(deploy, /old_recipients = by_code\.get\(code, \{\}\)\.get\('recipients'\)/) assert.match(deploy, /project\['recipients'\] = list\(old_recipients\)/) // 家具系统已接入生产;正式登记进初始化清单,防止重部署覆盖。 assert.match(deploy, /'furniture_platform'/) assert.match(deploy, /'家具业务系统'/) assert.match(deploy, /'script_monitor'/) assert.match(deploy, /'脚本监控'/) // 未列出的已登记项目必须原样保留,杜绝同类覆盖事故。 assert.match(deploy, /known_codes = \{item\['code'\] for item in projects\}/) assert.match(deploy, /docker pause youyidian-notification-center/) assert.match(deploy, /docker cp youyidian-notification-center:\/app\/data\/\. "\$data_backup\/"/) assert.match(deploy, /test -s "\$data_backup\/notifications\.db"/) assert.match(deploy, /docker compose build --pull=false/) assert.match(deploy, /docker compose up -d --no-build --force-recreate/) assert.doesNotMatch(deploy, /docker image inspect/) assert.match(gitDeploy, /docker pause youyidian-notification-center/) assert.match(gitDeploy, /docker cp youyidian-notification-center:\/app\/data\/\. "\$data_backup\/"/) assert.match(gitDeploy, /notification-data-before-git-release-\$stamp/) assert.match(gitDeploy, /test -s "\$data_backup\/notifications\.db"/) assert.match(gitDeploy, /SQLite 备份失败,拒绝重建生产容器/) assert.ok( gitDeploy.indexOf('docker cp youyidian-notification-center:/app/data/.') < gitDeploy.indexOf('docker compose up -d --no-build --force-recreate'), ) assert.equal(packageJson.scripts.test, 'node scripts/run-tests.mjs') assert.match(testRunner, /mkdtempSync/) assert.match(testRunner, /DATABASE_URL: databaseUrl/) assert.match(testRunner, /'migrate', 'deploy'/) assert.match(testRunner, /finally/) assert.match(testRunner, /rmSync\(resolvedTestRoot, \{ recursive: true, force: true \}\)/) })