This commit is contained in:
2026-05-31 16:03:55 +02:00
commit 4898b6ab27
4 changed files with 1171 additions and 0 deletions

17
go.mod Normal file
View File

@@ -0,0 +1,17 @@
module git.petrovv.com/go-migrate
go 1.26.2
require (
github.com/jackc/pgx/v5 v5.6.0
github.com/joho/godotenv v1.5.1
)
require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/text v0.14.0 // indirect
)

30
go.sum Normal file
View File

@@ -0,0 +1,30 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

1003
lib/lib.go Normal file

File diff suppressed because it is too large Load Diff

121
main.go Normal file
View File

@@ -0,0 +1,121 @@
package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"git.petrovv.com/go-migrate/lib"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/joho/godotenv"
)
func main() {
// Parse flags
schemaDir := flag.String("dir", "schema", "Directory containing desired schema SQL files")
cmd := flag.String("cmd", "", "Command: generate or apply")
flag.Parse()
if *cmd == "" {
fmt.Println("Usage:")
fmt.Println(" go run main.go -cmd=generate -dir=schema - Compare schema and generate migrations")
fmt.Println(" go run main.go -cmd=apply -dir=schema - Apply pending migrations")
fmt.Println("\nFlags:")
flag.PrintDefaults()
return
}
switch *cmd {
case "generate":
generateMigrations(*schemaDir)
case "apply":
applyMigrations(*schemaDir)
default:
fmt.Println("Unknown command:", *cmd)
fmt.Println("Use 'generate' or 'apply'")
}
}
func generateMigrations(schemaDir string) {
_ = godotenv.Load()
db := getDBConnection()
defer db.Close()
ctx := context.Background()
migrations, err := lib.GetMigrations(ctx, db, schemaDir)
if err != nil {
log.Fatal(err)
}
if len(migrations) == 0 {
fmt.Println("✓ Database schema is up to date")
return
}
fmt.Println("-- Migration SQL")
for _, m := range migrations {
fmt.Println(m)
}
}
func applyMigrations(schemaDir string) {
_ = godotenv.Load()
db := getDBConnection()
defer db.Close()
ctx := context.Background()
migrations, err := lib.GetMigrations(ctx, db, schemaDir)
if err != nil {
log.Fatal(err)
}
if len(migrations) == 0 {
fmt.Println("✓ Database schema is up to date")
return
}
fmt.Println("Applying migrations...")
for _, m := range migrations {
fmt.Printf("Executing: %s\n", m)
_, err := db.Exec(ctx, m)
if err != nil {
log.Fatalf("failed to execute %s: %v", m, err)
}
}
fmt.Println("✓ All migrations applied successfully")
}
func getDBConnection() *pgxpool.Pool {
dbUser := os.Getenv("DB_USER")
dbPass := os.Getenv("DB_PASS")
dbHost := os.Getenv("DB_HOST")
dbPort := os.Getenv("DB_PORT")
dbName := os.Getenv("DB_NAME")
if dbUser == "" {
dbUser = "hengspot_user"
}
if dbPass == "" {
dbPass = "securepassword"
}
if dbHost == "" {
dbHost = "localhost"
}
if dbPort == "" {
dbPort = "5432"
}
if dbName == "" {
dbName = "hengspot_db"
}
dsn := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", dbUser, dbPass, dbHost, dbPort, dbName)
pool, err := pgxpool.New(context.Background(), dsn)
if err != nil {
log.Fatalf("Unable to connect to database: %v", err)
}
return pool
}