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:
17
Makefile
17
Makefile
@@ -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!"
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user