From 093f0ca14ad5157f94dec38a529ce331d7dfea42 Mon Sep 17 00:00:00 2001 From: Glore Zeng Date: Mon, 19 Oct 2026 07:39:17 +0800 Subject: [PATCH] chore: add local development and build foundation --- .gitea/workflows/build.yml | 22 ++++++++++++++++++++++ README.md | 7 +++++++ scripts/check-migrations.mjs | 13 +++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 .gitea/workflows/build.yml create mode 100644 README.md create mode 100644 scripts/check-migrations.mjs diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..5ee78b3 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,22 @@ +name: build +on: + push: + branches: [main, develop, 'feature/**'] + tags: ['v*'] + pull_request: + branches: [main, develop] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22.22.0' + - run: node --version + - run: node scripts/check-migrations.mjs + - uses: actions/upload-artifact@v3 + with: + name: migrations-${{ github.sha }} + path: "*.up.sql" + if-no-files-found: error diff --git a/README.md b/README.md new file mode 100644 index 0000000..9460dbf --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# 数据库迁移 + +这些文件是历史增量,不是完整数据库。运行全部迁移前,必须导入经授权的脱敏基础结构,至少存在 `users.teacher`;其他业务表依赖私有 dbtable 模块,也需核对。不要用虚构的 users 表冒充完整初始化。 + +在上级工作区运行 `./scripts/workspace.ps1 migrate`,使用隔离的本地 MySQL 和 golang-migrate 记录版本。已有数据库须先核对 schema_migrations 与实际结构;禁止盲目 force。已执行的 SQL 不修改,新变更新增时间戳文件。 + +`node scripts/check-migrations.mjs` 仅检查命名、版本唯一性和非空。SQL 是否可执行须在脱敏基线数据库验证。现有迁移无 down 脚本,生产回退依赖经验证的备份恢复或补偿迁移,不自动回滚。 diff --git a/scripts/check-migrations.mjs b/scripts/check-migrations.mjs new file mode 100644 index 0000000..666a36b --- /dev/null +++ b/scripts/check-migrations.mjs @@ -0,0 +1,13 @@ +import { readdirSync, readFileSync } from 'node:fs'; +import assert from 'node:assert/strict'; +const files = readdirSync('.').filter(f => f.endsWith('.sql')).sort(); +assert(files.length > 0, 'No migrations'); +const versions = new Set(); +for (const file of files) { + const match = /^(\d+)_[a-z0-9_]+\.up\.sql$/.exec(file); + assert(match, `Invalid migration filename: ${file}`); + assert(!versions.has(match[1]), `Duplicate version: ${file}`); + versions.add(match[1]); + assert(readFileSync(file, 'utf8').trim(), `Empty migration: ${file}`); +} +console.log(`${files.length} migration files checked (structure only; MySQL execution still required).`);