Files
easyai/scripts/test-legacy-deployment-update.py
T
wangbo e29d203bb7
Test deployment public URL (Linux) / test-linux (push) Canceled after 0s
Test start.ps1 (Windows) / test-windows (push) Canceled after 0s
fix(deploy): 兼容旧配置迁移并支持固定版本验收
2026-10-03 07:56:12 +08:00

118 lines
5.9 KiB
Python

#!/usr/bin/env python3
"""Real Git/config adoption regression; container mutation is not used here."""
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import time
source = Path(__file__).resolve().parent.parent
started = time.monotonic()
def run(args, root, env=None):
return subprocess.run(args, cwd=root, env=env, capture_output=True, text=True, timeout=30)
with tempfile.TemporaryDirectory(prefix='easyai-legacy-update-') as directory:
base = Path(directory)
root = base / 'easyai'
root.mkdir()
(root / 'docker-compose.yml').write_text('services:\n easyai-server:\n image: server:old\n environment:\n - EXISTING=keep\n watchtower:\n image: watcher:old\n')
(root / '.gitignore').write_text('.env\ndata/\n')
(root / '.env').write_text('VERSION=old\nCONFIG_JWT_SECRET=keep-this-private-key\n')
for args in [['git','init','-q'], ['git','config','user.name','Update test'], ['git','config','user.email','test@example.invalid'], ['git','add','.'], ['git','commit','-qm','test: 旧部署基准']]:
assert run(args, root).returncode == 0
remote = base / 'remote.git'
seed = base / 'seed'
assert run(['git','clone','-q','--bare',str(root),str(remote)], base).returncode == 0
assert run(['git','remote','add','origin',str(remote)], root).returncode == 0
assert run(['git','fetch','-q'],root).returncode == 0
branch = run(['git','branch','--show-current'], root).stdout.strip()
assert run(['git','branch','--set-upstream-to','origin/'+branch],root).returncode == 0
assert run(['git','clone','-q',str(remote),str(seed)],base).returncode == 0
(seed / 'docker-compose.yml').write_text('''services:
easyai-server:
image: server:new
environment:
- EXISTING=keep
- MODEL_CONVERSION_WORKER_TOKEN=${MODEL_CONVERSION_WORKER_TOKEN}
watchtower:
image: watcher:new
easyai-updater:
image: updater:new
environment:
- UPDATE_MANIFEST_FILE=/etc/manifest.json
volumes:
- ./data/update-state:/state
- ./system-update/release-manifest.json:/etc/manifest.json:ro
networks:
easyai:
ipv4_address: 172.21.0.31
model-conversion-worker:
image: worker:new
networks:
easyai: {}
''')
(seed / 'scripts').mkdir()
(seed / 'scripts/init-security-env.sh').write_text('# modern security initializer\n')
(seed / 'demo.example.conf').write_text('# upstream example\n')
for args in [['git','config','user.name','Update test'],['git','config','user.email','test@example.invalid'],['git','add','.'],['git','commit','-qm','test: 新增转换服务与独立更新地址'],['git','push','-q']]:
assert run(args,seed).returncode == 0
with (root / 'docker-compose.yml').open('a') as stream:
stream.write(''' easyai-updater:
image: updater:new
environment:
- UPDATE_MANIFEST_FILE=/state/custom.json
volumes:
- ./data/update-state:/state
networks:
- easyai
''')
(root / 'scripts').mkdir()
(root / 'scripts/init-security-env.sh').write_text('# local legacy initializer\n')
(root / 'demo.example.conf').write_text('# custom nginx source; active copy elsewhere\n')
original = (root / 'docker-compose.yml').read_bytes()
bins = base / 'bin'
bins.mkdir()
docker = bins / 'docker'
docker.write_text('#!/bin/sh\nexit 0\n')
docker.chmod(0o755)
env = {**os.environ, 'PATH': str(bins)+os.pathsep+os.environ['PATH']}
legacy = run(['git','pull','--ff-only'],root)
assert legacy.returncode != 0 and 'would be overwritten' in legacy.stderr
assert original == (root / 'docker-compose.yml').read_bytes()
(root / 'business.js').write_text('local business code\n')
assert run(['git','add','business.js'],root).returncode == 0
rejected = run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
assert rejected.returncode != 0
assert original == (root / 'docker-compose.yml').read_bytes()
assert run(['git','reset','-q','HEAD','--','business.js'],root).returncode == 0
accepted = run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
assert accepted.returncode == 0, accepted.stdout+accepted.stderr
assert run(['git','pull','--ff-only'],root).returncode == 0
assert run(['git','diff','--name-only'],root).stdout == ''
override=json.loads((root/'data/deployment-config/legacy-compose.json').read_text())
assert override == {'services': {'easyai-updater': {'environment': {'UPDATE_MANIFEST_FILE': '/state/custom.json'}}}}, override
assert 'COMPOSE_FILE=docker-compose.yml:data/deployment-config/legacy-compose.json' in (root/'.env').read_text()
assert 'CONFIG_JWT_SECRET=keep-this-private-key' in (root/'.env').read_text()
backups=list((root/'data/deployment-backups').glob('legacy-update-*'))
assert len(backups)==1
assert (backups[0]/'docker-compose.yml').read_bytes()==original
assert (backups[0]/'demo.example.conf').read_text().startswith('# custom nginx')
assert (backups[0]/'.env').stat().st_mode & 0o077 == 0
assert (backups[0]).stat().st_mode & 0o077 == 0
resolved=run(['docker','compose','--env-file','.env','config','--format','json'],root)
assert resolved.returncode==0,resolved.stderr
config=json.loads(resolved.stdout)
assert config['services']['easyai-updater']['networks']['easyai']['ipv4_address']=='172.21.0.31'
assert config['services']['easyai-updater']['environment']['UPDATE_MANIFEST_FILE']=='/state/custom.json'
assert 'model-conversion-worker' in config['services']
repeat=run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
assert repeat.returncode==0
assert len(list((root/'data/deployment-backups').glob('legacy-update-*')))==1
print('legacy Git conflict: reproduced; code guard, private backups, local override, new Worker and updater address passed')
print(json.dumps({'passed':True,'durationSeconds':round(time.monotonic()-started,3)}))