601451f22b
Overlay ~150 upstream items onto our V8.12 base, preserving trade-pro
theme, registry tests, and design docs. Re-applied our patch set
(discovery/env_for/blocks.css/type-mapping/theme_color/frontend entries,
test_theme_pro_v3 mods) — all anchors survived upstream evolution.
New platform enhancement (fixes upgrade-introduced regression):
multilingual.site_locale now honors settings_json.locale, plus
PUT /api/i18n/sites/{id}/locale — standalone English sites get
<html lang='en'> under the V8.15 locale-rewrite pipeline.
compose: adopt V8.21.3 (image 8.21.3-dev.1, /api/ready probes, MySQL/S3
env) with project name pinned to siteforge-v8-10 (data volumes).
Tests: 356 passed / 11 failed — all 11 confirmed pre-existing in
pristine V8.21.3 on this host (10 upstream Windows env + our build test
now green after locale fix). Patch registry updated in plan doc.
Co-Authored-By: Claude Code <noreply@anthropic.com>
69 lines
3.4 KiB
Python
69 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""REAL PostgreSQL data migration CI smoke with a disposable isolated target.
|
|
|
|
This script deliberately never runs on ambiguous production-looking DB names.
|
|
Set SITEFORGE_ALLOW_PG_DATA_SMOKE=1 and database suffix _ci/_test.
|
|
"""
|
|
# Allow direct `python scripts/name.py` from a fresh source checkout.
|
|
import sys as _sys
|
|
from pathlib import Path as _Path
|
|
_sys.path.insert(0, str(_Path(__file__).resolve().parents[1]))
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import uuid
|
|
from pathlib import Path
|
|
from urllib.parse import unquote,urlsplit
|
|
|
|
from app import db
|
|
from app.sqlite_pg_transfer import migrate
|
|
from app.pg_disaster_recovery import RecoveryError
|
|
|
|
url = os.environ.get('SITEFORGE_DATABASE_URL','')
|
|
name = unquote(urlsplit(url).path.lstrip('/'))
|
|
if not db.POSTGRES or os.environ.get('SITEFORGE_ALLOW_PG_DATA_SMOKE')!='1' or not name.endswith(('_ci','_test')):
|
|
raise SystemExit('Requires explicit CI-only PG smoke flag and _ci/_test database')
|
|
|
|
with tempfile.TemporaryDirectory(prefix='sf-v818-ci-') as temp:
|
|
source=Path(temp)/'siteforge.sqlite3'
|
|
env=os.environ.copy(); env.pop('SITEFORGE_DATABASE_URL',None)
|
|
env['SITEFORGE_DATA_DIR']=temp
|
|
env['SITEFORGE_DB_FILE']=str(source)
|
|
marker='migration-smoke-'+uuid.uuid4().hex[:10]
|
|
code=r'''from app import (db,enterprise,factory_api,migration_audit,reusables,release_api,
|
|
cms_pipeline,v8_workflows,v8_templates,wp_migration_v81,wp_migration_v82,
|
|
wp_migration_v83,connectors_v84,connectors_v85,studio_v86,site_design_v87,multilingual)
|
|
import os
|
|
assert not db.POSTGRES
|
|
assert not os.path.exists(db.DB_FILE)
|
|
db.init()
|
|
for x in (enterprise,factory_api,migration_audit,reusables,release_api,
|
|
cms_pipeline,v8_workflows,v8_templates,wp_migration_v81,wp_migration_v82,
|
|
wp_migration_v83,connectors_v84,connectors_v85,studio_v86,site_design_v87,multilingual):x.setup()
|
|
s=os.environ['V818_MARKER']
|
|
with db.connect() as c:
|
|
c.execute('INSERT INTO sites(id,name,created_at,updated_at) VALUES (?,?,?,?)',(s,'Migration Sample',db.now(),db.now()))
|
|
for i in range(3):
|
|
c.execute('INSERT INTO entries(id,site_id,type,title,route,slug,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)',
|
|
(s+'e'+str(i),s,'product','Migrated Car '+str(i),'/products/'+str(i)+'/','p'+str(i),db.now(),db.now()))
|
|
c.execute('INSERT INTO redirects(id,site_id,old_path,new_path) VALUES (?,?,?,?)',(s+'r',s,'/old/','/products/0/'))
|
|
'''
|
|
env['V818_MARKER']=marker
|
|
subprocess.run([sys.executable,'-c',code],check=True,env=env)
|
|
try:
|
|
result=migrate(source,confirmed_offline=True)
|
|
assert result['verified'] and result['details']['entries']['rows']==3
|
|
assert result['details']['redirects']['rows']==1
|
|
assert db.one('SELECT COUNT(*) AS n FROM entries WHERE site_id=?',(marker,))['n']==3
|
|
assert db.one('SELECT COUNT(*) AS n FROM redirects WHERE site_id=?',(marker,))['n']==1
|
|
# Re-running must fail: no duplicate rows, no silent upsert.
|
|
try:migrate(source,confirmed_offline=True)
|
|
except RecoveryError as exc:
|
|
assert 'not empty' in str(exc)
|
|
else:raise AssertionError('Migration unexpectedly allowed nonempty target')
|
|
print(f'PASS: actual PostgreSQL transfer {result["tables"]} tables, {result["records"]} records; rerun blocked')
|
|
finally:
|
|
with db.connect() as c:
|
|
c.execute('DELETE FROM sites WHERE id=?',(marker,))
|