chore: 接入 Prisma 迁移部署基线

This commit is contained in:
湛兮
2026-06-12 01:38:58 +08:00
parent 78f97fedf8
commit a21ec249b7
8 changed files with 537 additions and 68 deletions
+166
View File
@@ -0,0 +1,166 @@
#!/usr/bin/env bash
set -euo pipefail
SRC="${1:-}"
APP_DIR="/srv/www/devops-platform-api"
BACKUP_DIR="/srv/www/devops-platform-api-backups"
ENV_FILE="/etc/devops-platform-api.env"
PM2_NAME="devops-platform-api"
HEALTH_URL="http://127.0.0.1:4300/health"
TS="$(date +%Y%m%d%H%M%S)"
if [ -z "$SRC" ] || [ ! -d "$SRC" ]; then
echo "Usage: deploy-devops-platform-api-from-jenkins <jenkins-workspace>"
exit 2
fi
for required in "$SRC/dist/main.js" "$SRC/package.json" "$SRC/pnpm-lock.yaml" "$SRC/prisma" "$ENV_FILE"; do
if [ ! -e "$required" ]; then
echo "Missing $required"
exit 3
fi
done
run_prisma_migrations() {
if [ "${PRISMA_MIGRATE_DEPLOY_ENABLED:-true}" != "true" ]; then
echo "Skipping Prisma migrations because PRISMA_MIGRATE_DEPLOY_ENABLED is not true"
return
fi
set -a
. ./.env.production
set +a
local migration_state
migration_state="$(node <<'NODE'
const { PrismaClient } = require('@prisma/client');
const requiredTables = [
'agent_invocations',
'audit_logs',
'deploy_jobs',
'deploy_runs',
'environments',
'outbox_messages',
'platform_messages',
'project_member_permissions',
'projects',
'run_steps',
'secrets',
'users',
];
const baselineMigrations = [
'20260611000000_baseline_current_schema',
'20260611120000_auth_members_messages',
];
const prisma = new PrismaClient();
async function main() {
const tables = await prisma.$queryRaw`
select table_name
from information_schema.tables
where table_schema = database()
`;
const existingTables = new Set(tables.map((row) => row.TABLE_NAME || row.table_name));
if (existingTables.size === 0) {
console.log('fresh');
return;
}
const missingTables = requiredTables.filter((name) => !existingTables.has(name));
if (missingTables.length > 0) {
console.error(`Existing database schema is incomplete; missing tables: ${missingTables.join(', ')}`);
process.exit(12);
}
const hasMigrationTable = existingTables.has('_prisma_migrations');
const appliedMigrations = hasMigrationTable
? await prisma.$queryRaw`select migration_name from _prisma_migrations`
: [];
const appliedNames = new Set(
appliedMigrations.map((row) => row.MIGRATION_NAME || row.migration_name),
);
const missingMigrations = baselineMigrations.filter((name) => !appliedNames.has(name));
if (missingMigrations.length > 0) {
console.log(`bootstrap:${missingMigrations.join(',')}`);
return;
}
console.log('ready');
}
main()
.finally(() => prisma.$disconnect());
NODE
)"
if [[ "$migration_state" == bootstrap:* ]]; then
local migrations_csv="${migration_state#bootstrap:}"
IFS=',' read -r -a missing_migrations <<< "$migrations_csv"
for migration in "${missing_migrations[@]}"; do
echo "Marking existing production schema migration as applied: $migration"
pnpm prisma migrate resolve --schema prisma/schema.prisma --applied "$migration"
done
else
echo "Prisma migration bootstrap state: $migration_state"
fi
echo "Running Prisma migrate deploy"
pnpm prisma migrate deploy --schema prisma/schema.prisma
}
mkdir -p "$BACKUP_DIR"
TMP="$(mktemp -d /srv/www/devops-platform-api.deploy.XXXXXX)"
OLD="$APP_DIR.old.$TS"
cp -a "$SRC/dist" "$TMP/dist"
cp -a "$SRC/prisma" "$TMP/prisma"
cp -a "$SRC/package.json" "$TMP/package.json"
cp -a "$SRC/pnpm-lock.yaml" "$TMP/pnpm-lock.yaml"
cp -a "$ENV_FILE" "$TMP/.env.production"
cd "$TMP"
corepack enable
corepack prepare pnpm@9.15.4 --activate
pnpm install --frozen-lockfile
pnpm prisma:generate
run_prisma_migrations
if [ -d "$APP_DIR" ]; then
tar -C "$APP_DIR" -czf "$BACKUP_DIR/$TS.tgz" .
mv "$APP_DIR" "$OLD"
fi
mv "$TMP" "$APP_DIR"
cd "$APP_DIR"
set -a
. ./.env.production
set +a
if ! pm2 restart "$PM2_NAME" --update-env; then
pm2 start dist/main.js --name "$PM2_NAME" --update-env
fi
sleep 8
if ! curl -fsS "$HEALTH_URL" >/dev/null; then
echo "Health check failed; rolling back $PM2_NAME"
pm2 stop "$PM2_NAME" || true
rm -rf "$APP_DIR.failed.$TS"
mv "$APP_DIR" "$APP_DIR.failed.$TS"
if [ -d "$OLD" ]; then
mv "$OLD" "$APP_DIR"
cd "$APP_DIR"
set -a
. ./.env.production
set +a
pm2 restart "$PM2_NAME" --update-env || pm2 start dist/main.js --name "$PM2_NAME" --update-env
fi
exit 5
fi
rm -rf "$OLD"
pm2 save >/dev/null
echo "Deployed devops-platform-api from $SRC to $APP_DIR"