package config import ( "flag" "strconv" "github.com/pkg/errors" ) type Flags struct { // Utility flags EnvDoc bool ShowEnv bool GenEnv string EnvFile string DevMode bool Staging bool // Database reset (destructive) ResetDB bool // Migration commands MigrateUp string MigrateRollback string MigrateStatus bool MigrateCreate string MigrateDryRun bool // Backup control MigrateNoBackup bool } func SetupFlags() (*Flags, error) { // Utility flags envDoc := flag.Bool("envdoc", false, "Print all environment variables and their documentation") showEnv := flag.Bool("showenv", false, "Print all environment variable values and their documentation") genEnv := flag.String("genenv", "", "Generate a .env file with all environment variables (specify filename)") envfile := flag.String("envfile", ".env", "Specify a .env file to use for the configuration") devMode := flag.Bool("dev", false, "Run the server in dev mode") staging := flag.Bool("staging", false, "Show a staging banner") // Database reset (destructive) resetDB := flag.Bool("reset-db", false, "⚠️ DESTRUCTIVE: Drop and recreate all tables (dev only)") // Migration commands migrateUp := flag.String("migrate-up", "", "Run pending database migrations (usage: --migrate-up [count|all], default: 1)") migrateRollback := flag.String("migrate-rollback", "", "Rollback migrations (usage: --migrate-rollback [count|all], default: 1)") migrateStatus := flag.Bool("migrate-status", false, "Show database migration status") migrateCreate := flag.String("migrate-create", "", "Create a new migration file with the given name") migrateDryRun := flag.Bool("migrate-dry-run", false, "Preview pending migrations without applying them") // Backup control migrateNoBackup := flag.Bool("no-backup", false, "Skip automatic backups (dev only - faster but less safe)") flag.Parse() // Validate: can't use multiple migration commands at once commands := 0 if *migrateUp != "" { commands++ } if *migrateRollback != "" { commands++ } if *migrateStatus { commands++ } if *migrateDryRun { commands++ } if *resetDB { commands++ } if commands > 1 { return nil, errors.New("cannot use multiple migration commands simultaneously") } // Validate migration count values if *migrateUp != "" { if err := validateMigrationCount(*migrateUp); err != nil { return nil, errors.Wrap(err, "invalid --migrate-up value") } } if *migrateRollback != "" { if err := validateMigrationCount(*migrateRollback); err != nil { return nil, errors.Wrap(err, "invalid --migrate-rollback value") } } flags := &Flags{ EnvDoc: *envDoc, ShowEnv: *showEnv, GenEnv: *genEnv, EnvFile: *envfile, DevMode: *devMode, Staging: *staging, ResetDB: *resetDB, MigrateUp: *migrateUp, MigrateRollback: *migrateRollback, MigrateStatus: *migrateStatus, MigrateCreate: *migrateCreate, MigrateDryRun: *migrateDryRun, MigrateNoBackup: *migrateNoBackup, } return flags, nil } // validateMigrationCount validates a migration count value // Valid values: "all" or a positive integer (1, 2, 3, ...) func validateMigrationCount(value string) error { if value == "" { return nil } if value == "all" { return nil } // Try parsing as integer count, err := strconv.Atoi(value) if err != nil { return errors.New("must be a positive integer or 'all'") } if count < 1 { return errors.New("must be a positive integer (1 or greater)") } return nil }