From 179897ba6f5a6b489fa1ea81be44aa766e44dbba Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 18 Jun 2026 13:34:02 +0800 Subject: [PATCH] fix(migrations): make all migrations idempotent; distinguish applied vs error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 006: ADD COLUMN 补 IF NOT EXISTS - 002: 5 个索引(status_published/slug_unique/post_tags_post/post_tags_tag/cover)补 IF NOT EXISTS - migrate.sh: 区分「已应用」与「真出错」,真错误时打印输出并中止,不再静默吞掉(M6) 已验证:第二次运行全部 OK(幂等),不再出现重复对象错误。 --- migrate.sh | 14 ++++++++++++-- migrations/002_posts.sql | 10 +++++----- migrations/006_add_toc_html.sql | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/migrate.sh b/migrate.sh index b1c8a11..14e49ee 100755 --- a/migrate.sh +++ b/migrate.sh @@ -66,10 +66,20 @@ echo "$MIGRATION_FILES" | sort | while IFS= read -r file; do filename=$(basename "$file") echo -n "[$filename] ... " - if psql "$DATABASE_URL" -f "$file" > /dev/null 2>&1; then + # 区分「已应用」与「真出错」:迁移本身已幂等(IF NOT EXISTS),正常应返回 0。 + # 非零退出码视为真错误,打印输出并中止,避免静默吞错(M6)。 + err_output=$(psql "$DATABASE_URL" -f "$file" 2>&1 >/dev/null) + rc=$? + + if [[ $rc -eq 0 ]]; then echo "OK" + elif echo "$err_output" | grep -qiE "already exists|duplicate|multiple primary keys"; then + echo "SKIPPED (already applied)" else - echo "SKIPPED (already applied or error)" + echo "FAIL" + echo "$err_output" | head -5 | sed 's/^/ /' + echo "Migration aborted due to error in $filename" + exit 1 fi done diff --git a/migrations/002_posts.sql b/migrations/002_posts.sql index 111a0bb..0a1f24b 100644 --- a/migrations/002_posts.sql +++ b/migrations/002_posts.sql @@ -20,8 +20,8 @@ CREATE TABLE IF NOT EXISTS posts ( CONSTRAINT posts_status_check CHECK (status IN ('draft', 'published')) ); -CREATE INDEX idx_posts_status_published ON posts(status, published_at DESC) WHERE deleted_at IS NULL; -CREATE UNIQUE INDEX idx_posts_slug_unique ON posts(slug) WHERE deleted_at IS NULL; +CREATE INDEX IF NOT EXISTS idx_posts_status_published ON posts(status, published_at DESC) WHERE deleted_at IS NULL; +CREATE UNIQUE INDEX IF NOT EXISTS idx_posts_slug_unique ON posts(slug) WHERE deleted_at IS NULL; CREATE TABLE IF NOT EXISTS tags ( id SERIAL PRIMARY KEY, @@ -34,8 +34,8 @@ CREATE TABLE IF NOT EXISTS post_tags ( PRIMARY KEY (post_id, tag_id) ); -CREATE INDEX idx_post_tags_post ON post_tags(post_id); -CREATE INDEX idx_post_tags_tag ON post_tags(tag_id); +CREATE INDEX IF NOT EXISTS idx_post_tags_post ON post_tags(post_id); +CREATE INDEX IF NOT EXISTS idx_post_tags_tag ON post_tags(tag_id); -- 为封面图添加索引 -CREATE INDEX idx_posts_cover ON posts(cover_image) WHERE cover_image IS NOT NULL; \ No newline at end of file +CREATE INDEX IF NOT EXISTS idx_posts_cover ON posts(cover_image) WHERE cover_image IS NOT NULL; \ No newline at end of file diff --git a/migrations/006_add_toc_html.sql b/migrations/006_add_toc_html.sql index 7caffb7..c670a36 100644 --- a/migrations/006_add_toc_html.sql +++ b/migrations/006_add_toc_html.sql @@ -1 +1 @@ -ALTER TABLE posts ADD COLUMN toc_html TEXT; +ALTER TABLE posts ADD COLUMN IF NOT EXISTS toc_html TEXT;