""" Test data seeding for development environment. """ import hashlib import logging from sqlalchemy.orm import Session from .models import Project, Package, Artifact, Tag, Upload, PackageVersion, ArtifactDependency, Team, TeamMembership, User from .storage import get_storage logger = logging.getLogger(__name__) # Test data definitions TEST_PROJECTS = [ { "name": "frontend-libs", "description": "Shared frontend libraries and components", "is_public": True, "packages": [ { "name": "ui-components", "description": "Reusable UI component library", }, { "name": "design-tokens", "description": "Design system tokens and variables", }, ], }, { "name": "backend-services", "description": "Backend microservices and shared utilities", "is_public": True, "packages": [ { "name": "auth-lib", "description": "Authentication and authorization library", }, { "name": "common-utils", "description": "Common utility functions", }, { "name": "api-client", "description": "Generated API client library", }, ], }, { "name": "mobile-apps", "description": "Mobile application builds and assets", "is_public": True, "packages": [ { "name": "ios-release", "description": "iOS release builds", }, { "name": "android-release", "description": "Android release builds", }, ], }, { "name": "internal-tools", "description": "Internal development tools (private)", "is_public": False, "packages": [ { "name": "dev-scripts", "description": "Development automation scripts", }, ], }, ] # Sample artifacts to create (content, tags, version) TEST_ARTIFACTS = [ { "project": "frontend-libs", "package": "ui-components", "content": b"/* UI Components v1.0.0 */\nexport const Button = () => {};\nexport const Input = () => {};\n", "filename": "ui-components-1.0.0.js", "content_type": "application/javascript", "tags": ["v1.0.0", "latest"], "version": "1.0.0", }, { "project": "frontend-libs", "package": "ui-components", "content": b"/* UI Components v1.1.0 */\nexport const Button = () => {};\nexport const Input = () => {};\nexport const Modal = () => {};\n", "filename": "ui-components-1.1.0.js", "content_type": "application/javascript", "tags": ["v1.1.0"], "version": "1.1.0", }, { "project": "frontend-libs", "package": "design-tokens", "content": b'{"colors": {"primary": "#007bff", "secondary": "#6c757d"}, "spacing": {"sm": "8px", "md": "16px"}}', "filename": "tokens.json", "content_type": "application/json", "tags": ["v1.0.0", "latest"], "version": "1.0.0", }, { "project": "backend-services", "package": "common-utils", "content": b"# Common Utils\n\ndef format_date(dt):\n return dt.isoformat()\n\ndef slugify(text):\n return text.lower().replace(' ', '-')\n", "filename": "utils-2.0.0.py", "content_type": "text/x-python", "tags": ["v2.0.0", "stable", "latest"], "version": "2.0.0", }, { "project": "backend-services", "package": "auth-lib", "content": b"package auth\n\nfunc ValidateToken(token string) bool {\n return len(token) > 0\n}\n", "filename": "auth-lib-1.0.0.go", "content_type": "text/x-go", "tags": ["v1.0.0", "latest"], "version": "1.0.0", }, ] # Dependencies to create (source artifact -> dependency) # Format: (source_project, source_package, source_version, dep_project, dep_package, version_constraint, tag_constraint) TEST_DEPENDENCIES = [ # ui-components v1.1.0 depends on design-tokens v1.0.0 ("frontend-libs", "ui-components", "1.1.0", "frontend-libs", "design-tokens", "1.0.0", None), # auth-lib v1.0.0 depends on common-utils v2.0.0 ("backend-services", "auth-lib", "1.0.0", "backend-services", "common-utils", "2.0.0", None), # auth-lib v1.0.0 also depends on design-tokens (stable tag) ("backend-services", "auth-lib", "1.0.0", "frontend-libs", "design-tokens", None, "latest"), ] def is_database_empty(db: Session) -> bool: """Check if the database has any projects.""" return db.query(Project).first() is None def seed_database(db: Session) -> None: """Seed the database with test data.""" if not is_database_empty(db): logger.info("Database already has data, skipping seed") return logger.info("Seeding database with test data...") storage = get_storage() # Find or use admin user for team ownership admin_user = db.query(User).filter(User.username == "admin").first() team_owner_username = admin_user.username if admin_user else "seed-user" # Create a demo team demo_team = Team( name="Demo Team", slug="demo-team", description="A demonstration team with sample projects", created_by=team_owner_username, ) db.add(demo_team) db.flush() # Add admin user as team owner if they exist if admin_user: membership = TeamMembership( team_id=demo_team.id, user_id=admin_user.id, role="owner", invited_by=team_owner_username, ) db.add(membership) db.flush() logger.info(f"Created team: {demo_team.name} ({demo_team.slug})") # Create projects and packages project_map = {} package_map = {} for project_data in TEST_PROJECTS: project = Project( name=project_data["name"], description=project_data["description"], is_public=project_data["is_public"], created_by=team_owner_username, team_id=demo_team.id, # Assign to demo team ) db.add(project) db.flush() # Get the ID project_map[project_data["name"]] = project for package_data in project_data["packages"]: package = Package( project_id=project.id, name=package_data["name"], description=package_data["description"], ) db.add(package) db.flush() package_map[(project_data["name"], package_data["name"])] = package logger.info(f"Created {len(project_map)} projects and {len(package_map)} packages (assigned to {demo_team.slug})") # Create artifacts, tags, and versions artifact_count = 0 tag_count = 0 version_count = 0 for artifact_data in TEST_ARTIFACTS: project = project_map[artifact_data["project"]] package = package_map[(artifact_data["project"], artifact_data["package"])] content = artifact_data["content"] sha256_hash = hashlib.sha256(content).hexdigest() size = len(content) s3_key = f"fruits/{sha256_hash[:2]}/{sha256_hash[2:4]}/{sha256_hash}" # Store in S3 try: storage.client.put_object( Bucket=storage.bucket, Key=s3_key, Body=content, ) except Exception as e: logger.warning(f"Failed to store artifact in S3: {e}") continue # Calculate ref_count: tags + version (if present) ref_count = len(artifact_data["tags"]) if artifact_data.get("version"): ref_count += 1 # Create artifact record artifact = Artifact( id=sha256_hash, size=size, content_type=artifact_data["content_type"], original_name=artifact_data["filename"], created_by=team_owner_username, s3_key=s3_key, ref_count=ref_count, ) db.add(artifact) # Create upload record upload = Upload( artifact_id=sha256_hash, package_id=package.id, original_name=artifact_data["filename"], uploaded_by="seed-user", ) db.add(upload) artifact_count += 1 # Create version record if specified if artifact_data.get("version"): version = PackageVersion( package_id=package.id, artifact_id=sha256_hash, version=artifact_data["version"], version_source="explicit", created_by=team_owner_username, ) db.add(version) version_count += 1 # Create tags for tag_name in artifact_data["tags"]: tag = Tag( package_id=package.id, name=tag_name, artifact_id=sha256_hash, created_by=team_owner_username, ) db.add(tag) tag_count += 1 db.flush() # Create dependencies dependency_count = 0 for dep_data in TEST_DEPENDENCIES: src_project, src_package, src_version, dep_project, dep_package, version_constraint, tag_constraint = dep_data # Find the source artifact by looking up its version src_pkg = package_map.get((src_project, src_package)) if not src_pkg: logger.warning(f"Source package not found: {src_project}/{src_package}") continue # Find the artifact for this version src_version_record = db.query(PackageVersion).filter( PackageVersion.package_id == src_pkg.id, PackageVersion.version == src_version, ).first() if not src_version_record: logger.warning(f"Source version not found: {src_project}/{src_package}@{src_version}") continue # Create the dependency dependency = ArtifactDependency( artifact_id=src_version_record.artifact_id, dependency_project=dep_project, dependency_package=dep_package, version_constraint=version_constraint, tag_constraint=tag_constraint, ) db.add(dependency) dependency_count += 1 db.commit() logger.info(f"Created {artifact_count} artifacts, {tag_count} tags, {version_count} versions, and {dependency_count} dependencies") logger.info("Database seeding complete")