fix: make db-reset work in non-interactive mode

- Add FORCE_RESET environment variable to skip confirmation prompt
- Update Makefile db-reset target to use FORCE_RESET=true
- Handle EOFError gracefully with helpful message
- Fix duplicate translation creation in seed script
- Check for existing translations before inserting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-12 22:36:49 +01:00
parent 48ff56a993
commit 65f296e883
2 changed files with 63 additions and 18 deletions

View File

@@ -14,6 +14,9 @@ endif
PYTHON := python PYTHON := python
PIP := pip PIP := pip
# Set PYTHONPATH for scripts
export PYTHONPATH := $(shell pwd)
# ============================================================================= # =============================================================================
# INSTALLATION & SETUP # INSTALLATION & SETUP
# ============================================================================= # =============================================================================
@@ -141,7 +144,19 @@ db-setup: migrate-up init-prod seed-demo
@echo "✅ Database setup complete!" @echo "✅ Database setup complete!"
@echo "✨ Run 'make dev' to start development server" @echo "✨ Run 'make dev' to start development server"
db-reset: migrate-down migrate-up init-prod seed-demo-reset db-reset:
@echo "⚠️ WARNING: This will DELETE ALL existing data!"
ifeq ($(DETECTED_OS),Windows)
@set SEED_MODE=reset&& set FORCE_RESET=true&& $(PYTHON) -m alembic downgrade -1
@set SEED_MODE=reset&& set FORCE_RESET=true&& $(PYTHON) -m alembic upgrade head
@set SEED_MODE=reset&& set FORCE_RESET=true&& $(PYTHON) scripts/init_production.py
@set SEED_MODE=reset&& set FORCE_RESET=true&& $(PYTHON) scripts/seed_demo.py
else
$(PYTHON) -m alembic downgrade -1
$(PYTHON) -m alembic upgrade head
$(PYTHON) scripts/init_production.py
SEED_MODE=reset FORCE_RESET=true $(PYTHON) scripts/seed_demo.py
endif
@echo "" @echo ""
@echo "✅ Database completely reset!" @echo "✅ Database completely reset!"

View File

@@ -21,10 +21,16 @@ Usage:
make seed-demo # Normal demo seeding make seed-demo # Normal demo seeding
make seed-demo-minimal # Minimal seeding (1 vendor only) make seed-demo-minimal # Minimal seeding (1 vendor only)
make seed-demo-reset # Delete all data and reseed (DANGEROUS!) make seed-demo-reset # Delete all data and reseed (DANGEROUS!)
make db-reset # Full reset (migrate down/up + init + seed reset)
Environment Variables:
SEED_MODE=normal|minimal|reset - Seeding mode (default: normal)
FORCE_RESET=true - Skip confirmation in reset mode (for non-interactive use)
This script is idempotent when run normally. This script is idempotent when run normally.
""" """
import argparse
import sys import sys
from datetime import UTC, datetime from datetime import UTC, datetime
from decimal import Decimal from decimal import Decimal
@@ -51,6 +57,7 @@ from models.database.company import Company
from models.database.customer import Customer, CustomerAddress from models.database.customer import Customer, CustomerAddress
from models.database.marketplace_import_job import MarketplaceImportJob from models.database.marketplace_import_job import MarketplaceImportJob
from models.database.marketplace_product import MarketplaceProduct from models.database.marketplace_product import MarketplaceProduct
from models.database.marketplace_product_translation import MarketplaceProductTranslation
from models.database.order import Order, OrderItem from models.database.order import Order, OrderItem
from models.database.product import Product from models.database.product import Product
from models.database.user import User from models.database.user import User
@@ -59,6 +66,7 @@ from models.database.vendor_domain import VendorDomain
from models.database.vendor_theme import VendorTheme from models.database.vendor_theme import VendorTheme
SEED_MODE = os.getenv("SEED_MODE", "normal") # normal, minimal, reset SEED_MODE = os.getenv("SEED_MODE", "normal") # normal, minimal, reset
FORCE_RESET = os.getenv("FORCE_RESET", "false").lower() in ("true", "1", "yes")
# ============================================================================= # =============================================================================
# DEMO DATA CONFIGURATION # DEMO DATA CONFIGURATION
@@ -243,11 +251,20 @@ def reset_all_data(db: Session):
print(" This will delete all vendors, customers, orders, etc.") print(" This will delete all vendors, customers, orders, etc.")
print(" Admin user will be preserved.") print(" Admin user will be preserved.")
# Get confirmation # Skip confirmation if FORCE_RESET is set (for non-interactive use)
response = input("\n Type 'DELETE ALL DATA' to confirm: ") if FORCE_RESET:
if response != "DELETE ALL DATA": print_warning("FORCE_RESET enabled - skipping confirmation")
print(" Reset cancelled.") else:
sys.exit(0) # Get confirmation interactively
try:
response = input("\n Type 'DELETE ALL DATA' to confirm: ")
if response != "DELETE ALL DATA":
print(" Reset cancelled.")
sys.exit(0)
except EOFError:
print_error("No interactive terminal available.")
print(" Use FORCE_RESET=true to skip confirmation in non-interactive mode.")
sys.exit(1)
# Delete in correct order (respecting foreign keys) # Delete in correct order (respecting foreign keys)
tables_to_clear = [ tables_to_clear = [
@@ -514,10 +531,10 @@ def create_demo_products(db: Session, vendor: Vendor, count: int) -> list[Produc
marketplace_product_id = f"{vendor.vendor_code}-MP-{i:04d}" marketplace_product_id = f"{vendor.vendor_code}-MP-{i:04d}"
product_id = f"{vendor.vendor_code}-PROD-{i:03d}" product_id = f"{vendor.vendor_code}-PROD-{i:03d}"
# Check if this product already exists # Check if this product already exists (by vendor_sku)
existing_product = ( existing_product = (
db.query(Product) db.query(Product)
.filter(Product.vendor_id == vendor.id, Product.product_id == product_id) .filter(Product.vendor_id == vendor.id, Product.vendor_sku == product_id)
.first() .first()
) )
@@ -538,9 +555,7 @@ def create_demo_products(db: Session, vendor: Vendor, count: int) -> list[Produc
# Create the MarketplaceProduct (base product data) # Create the MarketplaceProduct (base product data)
marketplace_product = MarketplaceProduct( marketplace_product = MarketplaceProduct(
marketplace_product_id=marketplace_product_id, marketplace_product_id=marketplace_product_id,
title=f"Sample Product {i} - {vendor.name}", source_url=f"https://{vendor.subdomain}.example.com/products/sample-{i}",
description=f"This is a demo product for testing purposes in {vendor.name}. High quality and affordable.",
link=f"https://{vendor.subdomain}.example.com/products/sample-{i}",
image_link=f"https://{vendor.subdomain}.example.com/images/product-{i}.jpg", image_link=f"https://{vendor.subdomain}.example.com/images/product-{i}.jpg",
price=str(Decimal(f"{(i * 10) % 500 + 9.99}")), # Store as string price=str(Decimal(f"{(i * 10) % 500 + 9.99}")), # Store as string
brand=vendor.name, brand=vendor.name,
@@ -557,19 +572,34 @@ def create_demo_products(db: Session, vendor: Vendor, count: int) -> list[Produc
db.add(marketplace_product) db.add(marketplace_product)
db.flush() # Flush to get the marketplace_product.id db.flush() # Flush to get the marketplace_product.id
# Check if English translation already exists
existing_translation = (
db.query(MarketplaceProductTranslation)
.filter(
MarketplaceProductTranslation.marketplace_product_id
== marketplace_product.id,
MarketplaceProductTranslation.language == "en",
)
.first()
)
if not existing_translation:
# Create English translation
translation = MarketplaceProductTranslation(
marketplace_product_id=marketplace_product.id,
language="en",
title=f"Sample Product {i} - {vendor.name}",
description=f"This is a demo product for testing purposes in {vendor.name}. High quality and affordable.",
)
db.add(translation)
# Create the Product (vendor-specific entry) # Create the Product (vendor-specific entry)
product = Product( product = Product(
vendor_id=vendor.id, vendor_id=vendor.id,
marketplace_product_id=marketplace_product.id, marketplace_product_id=marketplace_product.id,
product_id=product_id, vendor_sku=product_id, # Use vendor_sku for vendor's internal product reference
price=float(Decimal(f"{(i * 10) % 500 + 9.99}")), # Store as float price=float(Decimal(f"{(i * 10) % 500 + 9.99}")), # Store as float
availability="in stock",
condition="new",
currency="EUR",
is_active=True, is_active=True,
is_featured=(i % 5 == 0), # Every 5th product is featured
display_order=i,
min_quantity=1,
created_at=datetime.now(UTC), created_at=datetime.now(UTC),
updated_at=datetime.now(UTC), updated_at=datetime.now(UTC),
) )