Reviewed-on: #2 Reviewed-by: Cloud Administrator <cloud-admin@noreply.gitstormr.dev> Co-authored-by: Rene Nochebuena <code-raider@noreply.gitstormr.dev> Co-committed-by: Rene Nochebuena <code-raider@noreply.gitstormr.dev>
This commit is contained in:
parent
80f03102e2
commit
ff1fc8ca0c
50
.gitea/workflows/ci-basic.yml
Normal file
50
.gitea/workflows/ci-basic.yml
Normal file
@ -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 ./...
|
50
.gitea/workflows/ci-protected.yml
Normal file
50
.gitea/workflows/ci-protected.yml
Normal file
@ -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 ./...
|
43
.gitea/workflows/ci-tag.yml
Normal file
43
.gitea/workflows/ci-tag.yml
Normal file
@ -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 ./...
|
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -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
|
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GOROOT" url="file:///usr/local/go" />
|
||||||
|
</project>
|
4
.idea/vcs.xml
generated
Normal file
4
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||||
|
</project>
|
83
README.md
83
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! 🚀
|
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!")
|
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module gitstormr.dev/stone-utils/stonesql
|
||||||
|
|
||||||
|
go 1.24
|
||||||
|
|
||||||
|
require gitstormr.dev/stone-utils/stoneerror v1.0.0
|
2
go.sum
Normal file
2
go.sum
Normal file
@ -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=
|
106
migrator.go
Normal file
106
migrator.go
Normal file
@ -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
|
||||||
|
}
|
43
migrator_test.go
Normal file
43
migrator_test.go
Normal file
@ -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")
|
||||||
|
}
|
||||||
|
}
|
10
sonar-project.properties
Normal file
10
sonar-project.properties
Normal file
@ -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
|
8
test/embed.go
Normal file
8
test/embed.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed *.sql
|
||||||
|
var TestFS embed.FS
|
1
test/test.sql
Normal file
1
test/test.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
SELECT 1 == 1;
|
Loading…
x
Reference in New Issue
Block a user