diff --git a/.gitea/workflows/ci-basic.yml b/.gitea/workflows/ci-basic.yml
new file mode 100644
index 0000000..b17134d
--- /dev/null
+++ b/.gitea/workflows/ci-basic.yml
@@ -0,0 +1,50 @@
+name: Go CI/CD
+run-name: ${{ github.actor }} is running CI/CD basic
+
+on:
+ push:
+ branches-ignore:
+ - main
+ - release/**
+ - develop
+ pull_request:
+ branches-ignore:
+ - main
+ - release/**
+ - develop
+
+jobs:
+ go-ci:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup go
+ uses: actions/setup-go@v5
+ with:
+ go-version: '1.24'
+
+ - name: Download dependencies
+ shell: bash
+ run: |
+ go mod tidy -x
+
+ - name: Run tests
+ shell: bash
+ run: |
+ go test -json > test-report.out
+ go test -coverprofile=coverage.out
+
+ - name: SonarQube Analysis
+ uses: SonarSource/sonarqube-scan-action@v5
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
+
+ - name: Build binary
+ shell: bash
+ run: |
+ go build ./...
\ No newline at end of file
diff --git a/.gitea/workflows/ci-protected.yml b/.gitea/workflows/ci-protected.yml
new file mode 100644
index 0000000..35994eb
--- /dev/null
+++ b/.gitea/workflows/ci-protected.yml
@@ -0,0 +1,50 @@
+name: Go CI/CD
+run-name: ${{ github.actor }} is running CI/CD protected
+
+on:
+ push:
+ branches:
+ - main
+ - release/**
+ - develop
+ pull_request:
+ branches:
+ - main
+ - release/**
+ - develop
+
+jobs:
+ go-ci:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup go
+ uses: actions/setup-go@v5
+ with:
+ go-version: '1.24'
+
+ - name: Download dependencies
+ shell: bash
+ run: |
+ go mod tidy -x
+
+ - name: Run tests
+ shell: bash
+ run: |
+ go test -json > test-report.out
+ go test -coverprofile=coverage.out
+
+ - name: SonarQube Analysis
+ uses: SonarSource/sonarqube-scan-action@v5
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
+
+ - name: Build binary
+ shell: bash
+ run: |
+ go build ./...
\ No newline at end of file
diff --git a/.gitea/workflows/ci-tag.yml b/.gitea/workflows/ci-tag.yml
new file mode 100644
index 0000000..7fcf0ea
--- /dev/null
+++ b/.gitea/workflows/ci-tag.yml
@@ -0,0 +1,43 @@
+name: Go CI/CD
+run-name: ${{ github.actor }} is running CI/CD Tag
+
+on:
+ push:
+ tags:
+ - '*'
+
+jobs:
+ go-ci:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup go
+ uses: actions/setup-go@v5
+ with:
+ go-version: '1.24'
+
+ - name: Download dependencies
+ shell: bash
+ run: |
+ go mod tidy -x
+
+ - name: Run tests
+ shell: bash
+ run: |
+ go test -json > test-report.out
+ go test -coverprofile=coverage.out
+
+ - name: SonarQube Analysis
+ uses: SonarSource/sonarqube-scan-action@v5
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
+
+ - name: Build binary
+ shell: bash
+ run: |
+ go build ./...
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..1c05705
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..d843f34
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 3aa2ac1..1298acb 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,82 @@
-# stonesql
+# StoneSQL - **10 BILLION% MIGRATION PRECISION!**
-StoneSQL - Ultimate SQL Migration Engine! ⚡ Scientific database versioning with atomic precision. Embedded migration files, error tracking & stone-utils integration. 10 billion% more reliable schema changes! 🚀
\ No newline at end of file
+Ultimate SQL Migration Engine! ⚡ Scientific database versioning with atomic precision. Embedded migration files, error tracking & stone-utils integration. 10 billion% more reliable schema changes! 🚀
+
+[]()
+[]()
+[]()
+
+## 🚀 Why StoneSQL?
+
+- **Embedded SQL migrations** with atomic precision
+- **Scientifically versioned** schema changes
+- **100% reproducible** database states
+- **10 billion schema changes/sec** (theoretical)
+
+## 💥 Installation
+
+```bash
+go get gitstormr.dev/stone-utils/stonesql@latest
+```
+
+## ⚡ Basic Usage
+
+```go
+package main
+
+import (
+ "embed"
+ "gitstormr.dev/stone-utils/stonesql"
+)
+
+//go:embed migrations/*.sql
+var migrations embed.FS
+
+type DBMigrator struct{}
+
+func (m *DBMigrator) ExecuteMigration(ctx context.Context, name, sql string) error {
+ // Execute with your favorite database driver
+ return nil
+}
+
+func main() {
+ if err := stonesql.RunMigrations(context.Background(), &DBMigrator{}, migrations, "migrations"); err != nil {
+ panic(err) // Handle error properly in production!
+ }
+}
+```
+
+## 🔬 Core Features
+
+### Embedded migration files
+
+```text
+migrations/
+├─ 001_init.sql
+├─ 002_add_users.sql
+└─ 003_add_indexes.sql
+```
+
+### Scientific error tracking
+
+```go
+ErrWalkDirFailed = stoneerror.New(2001, "failed walking migrations")
+ErrReadMigrationFailed = stoneerror.New(2002, "failed reading SQL file")
+// ...and more!
+```
+
+## ⚗️ Scientific Benchmarks
+
+| METRIC | STANDARD LIB | STONESQL |
+|-----------------|---------------|----------|
+| Reliability | 80% | 10B% |
+| Reproducibility | ❌ | ✅✅✅ |
+| Atomicity | Maybe | ALWAYS |
+
+**Join the Scientific Revolution!**
+
+> "This isn't just schema management - it's revolutionizing database evolution like we revived civilization!" - Senku Ishigami
+
+Kingdom of Science Approved
+
+(Now with 100% more Chrome screaming "SO BADASS!")
\ No newline at end of file
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..1795b20
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module gitstormr.dev/stone-utils/stonesql
+
+go 1.24
+
+require gitstormr.dev/stone-utils/stoneerror v1.0.0
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..d5a0ca6
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+gitstormr.dev/stone-utils/stoneerror v1.0.0 h1:EJpn4MZBeYifWlCoQBEGmGdEtNABjOrUzJmQSqcXqY0=
+gitstormr.dev/stone-utils/stoneerror v1.0.0/go.mod h1:Rs34Oz14ILsbkZ++Ov9PObTz7mRvyyvcCcML9AeyIyk=
diff --git a/migrator.go b/migrator.go
new file mode 100644
index 0000000..9d0121f
--- /dev/null
+++ b/migrator.go
@@ -0,0 +1,106 @@
+package stonesql
+
+import (
+ "context"
+ "embed"
+ "io/fs"
+ "path/filepath"
+
+ "gitstormr.dev/stone-utils/stoneerror"
+)
+
+// SQLFileExtension represents the file extension for SQL migration files.
+const (
+ SQLFileExtension = ".sql"
+)
+
+// ErrWalkDirFailed represents an error for failed directory traversal.
+// ErrReadMigrationFailed represents an error for reading migration files.
+// ErrExecuteMigrationFailed represents an error during migration execution.
+// ErrMigrationProcessFailed represents a general migration process failure.
+var (
+ ErrWalkDirFailed = stoneerror.New(
+ 2001,
+ "failed to walk migration directory",
+ )
+ ErrReadMigrationFailed = stoneerror.New(
+ 2002,
+ "failed to read migration file",
+ )
+ ErrExecuteMigrationFailed = stoneerror.New(
+ 2003,
+ "failed to execute migration",
+ )
+ ErrMigrationProcessFailed = stoneerror.New(
+ 2004,
+ "migration process failed",
+ )
+)
+
+// Migrator defines the interface for executing SQL migrations.
+// ExecuteMigration runs a migration given its name and SQL content.
+type Migrator interface {
+ ExecuteMigration(ctx context.Context, name string, sqlContent string) error
+}
+
+// RunMigrations performs a series of database migrations from embedded files.
+// It traverses the provided filesystem path, reads SQL files, and executes them.
+// If an error occurs during traversal, reading, or execution, it wraps and returns it.
+// Context to be used for execution is passed via the ctx parameter.
+// The migrator parameter executes individual SQL content for migrations.
+// The migrationsFS parameter provides an embedded filesystem for the SQL files.
+// The path parameter specifies the directory within the embedded FS to search in.
+// Returns an error if any step in the migration process fails.
+func RunMigrations(
+ ctx context.Context,
+ migrator Migrator,
+ migrationsFS embed.FS,
+ path string,
+) error {
+ walkErr := fs.WalkDir(
+ migrationsFS,
+ path,
+ func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return stoneerror.Wrap(
+ err, ErrWalkDirFailed.Code,
+ ErrWalkDirFailed.Message,
+ ).
+ WithMetadata("path", path)
+ }
+
+ if !d.IsDir() && filepath.Ext(path) == SQLFileExtension {
+ sqlContent, readErr := migrationsFS.ReadFile(path)
+ if readErr != nil {
+ return stoneerror.Wrap(
+ readErr, ErrReadMigrationFailed.Code,
+ ErrReadMigrationFailed.Message,
+ ).
+ WithMetadata("file", path)
+ }
+
+ if err = migrator.ExecuteMigration(
+ ctx, path, string(sqlContent),
+ ); err != nil {
+ return stoneerror.Wrap(
+ err, ErrExecuteMigrationFailed.Code,
+ ErrExecuteMigrationFailed.Message,
+ ).
+ WithMetadata("migration", path)
+ }
+ }
+
+ return nil
+ },
+ )
+
+ if walkErr != nil {
+ return stoneerror.Wrap(
+ walkErr, ErrMigrationProcessFailed.Code,
+ ErrMigrationProcessFailed.Message,
+ ).
+ WithMetadata("rootPath", path)
+ }
+
+ return nil
+}
diff --git a/migrator_test.go b/migrator_test.go
new file mode 100644
index 0000000..a0aa113
--- /dev/null
+++ b/migrator_test.go
@@ -0,0 +1,43 @@
+package stonesql
+
+import (
+ "context"
+ "fmt"
+ "testing"
+
+ "gitstormr.dev/stone-utils/stonesql/test"
+)
+
+type migratorSuccessMock struct{}
+
+func (m *migratorSuccessMock) ExecuteMigration(
+ ctx context.Context, name string, sqlContent string,
+) error {
+ fmt.Println(name, sqlContent)
+ return nil
+}
+
+type migratorFailureMock struct{}
+
+func (m *migratorFailureMock) ExecuteMigration(
+ ctx context.Context, name string, sqlContent string,
+) error {
+ return fmt.Errorf("failed to execute migration %s", name)
+}
+
+func Test_MigrationSuccess(t *testing.T) {
+ migrator := &migratorSuccessMock{}
+ err := RunMigrations(context.Background(), migrator, test.TestFS, ".")
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func Test_MigrationFailure(t *testing.T) {
+ migrator := &migratorFailureMock{}
+ err := RunMigrations(context.Background(), migrator, test.TestFS, ".")
+
+ if err == nil {
+ t.Error("expected error")
+ }
+}
diff --git a/sonar-project.properties b/sonar-project.properties
new file mode 100644
index 0000000..621a0f9
--- /dev/null
+++ b/sonar-project.properties
@@ -0,0 +1,10 @@
+sonar.projectKey=9abe63b7-edeb-482a-ac71-9f4afb2947b1
+sonar.projectName=stone-utils/stonesql
+sonar.language=go
+sonar.sources=.
+sonar.exclusions=**/*_test.go, test/**
+sonar.tests=.
+sonar.test.inclusions=**/*_test.go
+sonar.go.tests.reportPaths=test-report.out
+sonar.go.coverage.reportPaths=coverage.out
+sonar.qualitygate.wait=true
\ No newline at end of file
diff --git a/test/embed.go b/test/embed.go
new file mode 100644
index 0000000..7088ef1
--- /dev/null
+++ b/test/embed.go
@@ -0,0 +1,8 @@
+package test
+
+import (
+ "embed"
+)
+
+//go:embed *.sql
+var TestFS embed.FS
diff --git a/test/test.sql b/test/test.sql
new file mode 100644
index 0000000..ae116c9
--- /dev/null
+++ b/test/test.sql
@@ -0,0 +1 @@
+SELECT 1 == 1;
\ No newline at end of file