add(all): database migrations prod
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
_ "github.com/crusttech/crust/auth/db/mysql"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rakyll/statik/fs"
|
||||
"github.com/titpetric/factory"
|
||||
)
|
||||
|
||||
//go:generate statik -p mysql -Z -f -src=schema/mysql
|
||||
|
||||
func statements(contents []byte, err error) ([]string, error) {
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return regexp.MustCompilePOSIX(";$").Split(string(contents), -1), nil
|
||||
}
|
||||
|
||||
func Migrate(db *factory.DB) error {
|
||||
statikFS, err := fs.New()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error creating statik filesystem")
|
||||
}
|
||||
|
||||
var files []string
|
||||
|
||||
if err := fs.Walk(statikFS, "/", func(filename string, info os.FileInfo, err error) error {
|
||||
matched, err := filepath.Match("/*.up.sql", filename)
|
||||
if matched {
|
||||
files = append(files, filename)
|
||||
}
|
||||
return err
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "Error when listing files for migrations")
|
||||
}
|
||||
|
||||
sort.Strings(files)
|
||||
|
||||
if len(files) == 0 {
|
||||
return errors.New("No files encoded for migration, need at least one SQL file")
|
||||
}
|
||||
|
||||
migrate := func(filename string, useLog bool) error {
|
||||
status := migration{
|
||||
Project: "auth",
|
||||
Filename: filename,
|
||||
}
|
||||
if useLog {
|
||||
if err := db.Get(&status, "select * from migrations where project=? and filename=?", status.Project, status.Filename); err != nil {
|
||||
return err
|
||||
}
|
||||
if status.Status == "ok" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
up := func() error {
|
||||
stmts, err := statements(fs.ReadFile(statikFS, filename))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("Error reading migration %s", filename))
|
||||
}
|
||||
|
||||
log.Println("Running migration for", filename)
|
||||
for idx, query := range stmts {
|
||||
if strings.TrimSpace(query) != "" && idx >= status.StatementIndex {
|
||||
status.StatementIndex = idx
|
||||
if _, err := db.Exec(query); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Println("Migration done OK")
|
||||
status.Status = "ok"
|
||||
return nil
|
||||
}
|
||||
|
||||
err := db.Transaction(up)
|
||||
if err != nil {
|
||||
status.Status = err.Error()
|
||||
}
|
||||
if useLog {
|
||||
if err := db.Replace("migrations", status); err != nil {
|
||||
log.Println("replace failed", err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migrate("/migrations.sql", false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, filename := range files {
|
||||
if err := migrate(filename, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/titpetric/dockertest"
|
||||
"github.com/titpetric/factory"
|
||||
)
|
||||
|
||||
func TestMigrations(t *testing.T) {
|
||||
args := []string{
|
||||
// "--rm",
|
||||
"-e", "MYSQL_ROOT_PASSWORD=root",
|
||||
"-e", "MYSQL_DATABASE=test",
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second))
|
||||
defer cancel()
|
||||
|
||||
count := 0
|
||||
|
||||
mysql, err := dockertest.RunContainerContext(ctx, "titpetric/percona-xtrabackup", "3306", func(addr string) error {
|
||||
factory.Database.Add("default", "root:root@tcp("+addr+")/test?collation=utf8mb4_general_ci")
|
||||
log.Println(addr)
|
||||
_, err := factory.Database.Get()
|
||||
count++
|
||||
time.Sleep(time.Second)
|
||||
return err
|
||||
}, args...)
|
||||
defer mysql.Terminate() // Shutdown()
|
||||
if err != nil {
|
||||
t.Fatalf("Error starting mysql: %#v", err)
|
||||
}
|
||||
|
||||
db := factory.Database.MustGet()
|
||||
if err := Migrate(db); err != nil {
|
||||
t.Fatalf("Unexpected error: %#v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Code generated by statik. DO NOT EDIT.
|
||||
|
||||
// Package statik contains static assets.
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"github.com/rakyll/statik/fs"
|
||||
)
|
||||
|
||||
func init() {
|
||||
data := "PK\x03\x04\x14\x00\x08\x00\x00\x00WBAM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00 \x0020180704080000.base.up.sqlUT\x05\x00\x01g\xd8\xb1[CREATE TABLE settings (\n name VARCHAR(200) NOT NULL COMMENT 'Unique set of setting keys',\n value TEXT COMMENT 'Setting value',\n\n PRIMARY KEY (name)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- Keeps all known users, home and external organisation\n-- changes are stored in audit log\nCREATE TABLE users (\n id BIGINT UNSIGNED NOT NULL,\n email TEXT NOT NULL,\n username TEXT NOT NULL,\n password TEXT NOT NULL,\n name TEXT NOT NULL,\n handle TEXT NOT NULL,\n meta JSON NOT NULL,\n satosa_id CHAR(36) NULL,\n\n rel_organisation BIGINT UNSIGNED NOT NULL,\n\n created_at DATETIME NOT NULL DEFAULT NOW(),\n updated_at DATETIME NULL,\n suspended_at DATETIME NULL,\n deleted_at DATETIME NULL, -- user soft delete\n\n PRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE UNIQUE INDEX uid_satosa ON users (satosa_id);\nPK\x07\x08>\xa7\xd7\x12$\x04\x00\x00$\x04\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xc0kHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00migrations.sqlUT\x05\x00\x01\xd9[\xbb[CREATE TABLE IF NOT EXISTS `migrations` (\n `project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',\n `filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',\n `statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',\n `status` varchar(16) NOT NULL COMMENT 'ok or full error message',\n PRIMARY KEY (`project`,`filename`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08%l\xb2\x16\x7f\x01\x00\x00\x7f\x01\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00WBAM>\xa7\xd7\x12$\x04\x00\x00$\x04\x00\x00\x1a\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x0020180704080000.base.up.sqlUT\x05\x00\x01g\xd8\xb1[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xc0kHM%l\xb2\x16\x7f\x01\x00\x00\x7f\x01\x00\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81u\x04\x00\x00migrations.sqlUT\x05\x00\x01\xd9[\xbb[PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x96\x00\x00\x009\x06\x00\x00\x00\x00"
|
||||
fs.Register(data)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
CREATE TABLE IF NOT EXISTS `migrations` (
|
||||
`project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',
|
||||
`filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',
|
||||
`statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',
|
||||
`status` varchar(16) NOT NULL COMMENT 'ok or full error message',
|
||||
PRIMARY KEY (`project`,`filename`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package db
|
||||
|
||||
type migration struct {
|
||||
Project string `db:"project"`
|
||||
Filename string `db:"filename"`
|
||||
StatementIndex int `db:"statement_index"`
|
||||
Status string `db:"status"`
|
||||
}
|
||||
+9
-2
@@ -7,14 +7,15 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/SentimensRG/ctx/sigctx"
|
||||
"github.com/crusttech/crust/auth/rest"
|
||||
"github.com/crusttech/crust/auth/service"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/cors"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
migrate "github.com/crusttech/crust/auth/db"
|
||||
"github.com/crusttech/crust/auth/rest"
|
||||
"github.com/crusttech/crust/auth/service"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
)
|
||||
|
||||
@@ -30,6 +31,7 @@ func Init() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// @todo: profiling as an external service?
|
||||
switch flags.db.Profiler {
|
||||
case "stdout":
|
||||
@@ -38,6 +40,11 @@ func Init() error {
|
||||
fmt.Println("No database query profiler selected")
|
||||
}
|
||||
|
||||
// migrate database schema
|
||||
if err := migrate.Migrate(db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// configure resputil options
|
||||
resputil.SetConfig(resputil.Options{
|
||||
Pretty: flags.http.Pretty,
|
||||
|
||||
@@ -12,6 +12,11 @@ function gofmt {
|
||||
done
|
||||
}
|
||||
|
||||
echo "=== go generate ==="
|
||||
cd auth/db && go generate && cd ../..
|
||||
cd crm/db && go generate && cd ../..
|
||||
cd sam/db && go generate && cd ../..
|
||||
|
||||
_PWD=$PWD
|
||||
SPECS=$(find $PWD -name 'spec.json' | xargs -n1 dirname)
|
||||
for SPEC in $SPECS; do
|
||||
@@ -33,4 +38,5 @@ go run sam/types/permissions/main.go -package types -function "func (c *Organisa
|
||||
go run sam/types/permissions/main.go -package types -function "func (c *Team) Permissions() []rbac.OperationGroup" -input sam/types/permissions/2-team.json -output sam/types/team_perms.go
|
||||
go run sam/types/permissions/main.go -package types -function "func (c *Channel) Permissions() []rbac.OperationGroup" -input sam/types/permissions/3-channel.json -output sam/types/channel_perms.go
|
||||
|
||||
|
||||
gofmt
|
||||
|
||||
+8
-13
@@ -24,13 +24,6 @@ func statements(contents []byte, err error) ([]string, error) {
|
||||
return regexp.MustCompilePOSIX(";$").Split(string(contents), -1), nil
|
||||
}
|
||||
|
||||
type migration struct {
|
||||
Project string
|
||||
Filename string
|
||||
StatementIndex int `db:"statement_index"`
|
||||
Status string
|
||||
}
|
||||
|
||||
func Migrate(db *factory.DB) error {
|
||||
statikFS, err := fs.New()
|
||||
if err != nil {
|
||||
@@ -89,14 +82,16 @@ func Migrate(db *factory.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := db.Transaction(up); err != nil {
|
||||
err := db.Transaction(up)
|
||||
if err != nil {
|
||||
status.Status = err.Error()
|
||||
if useLog {
|
||||
db.Replace("migrations", status)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if useLog {
|
||||
if err := db.Replace("migrations", status); err != nil {
|
||||
log.Println("replace failed", err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migrate("/migrations.sql", false); err != nil {
|
||||
|
||||
@@ -8,6 +8,6 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
data := "PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00 \x0020180704080000.base.up.sqlUT\x05\x00\x01\xbcQ\xbb[CREATE TABLE `crm_content` (\n `id` bigint(20) unsigned NOT NULL,\n `module_id` bigint(20) unsigned NOT NULL,\n `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,\n `updated_at` datetime DEFAULT NULL,\n `archived_at` datetime DEFAULT NULL,\n `deleted_at` datetime DEFAULT NULL,\n PRIMARY KEY (`id`,`module_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_content_columns` (\n `content_id` bigint(20) NOT NULL,\n `column_name` varchar(255) NOT NULL,\n `column_value` text NOT NULL,\n PRIMARY KEY (`content_id`,`column_name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_fields` (\n `field_type` varchar(16) NOT NULL COMMENT 'Short field type (string, boolean,...)',\n `field_name` varchar(255) NOT NULL COMMENT 'Description of field contents',\n `field_template` varchar(255) NOT NULL COMMENT 'HTML template file for field',\n PRIMARY KEY (`field_type`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_module` (\n `id` bigint(20) unsigned NOT NULL,\n `name` varchar(64) NOT NULL COMMENT 'The name of the module',\n `json` json NOT NULL COMMENT 'List of field definitions for the module',\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_module_form` (\n `module_id` bigint(20) unsigned NOT NULL,\n `place` tinyint(3) unsigned NOT NULL,\n `type` varchar(64) NOT NULL COMMENT 'The type of the form input field',\n `name` varchar(64) NOT NULL COMMENT 'The name of the field in the form',\n `title` varchar(255) NOT NULL COMMENT 'The label of the form input',\n `placeholder` varchar(255) NOT NULL COMMENT 'Placeholder text (if supported by input)',\n PRIMARY KEY (`module_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08\xe9\xe8\x9a\xeex\x06\x00\x00x\x06\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00 \x0020180704080001.crm_fields-data.up.sqlUT\x05\x00\x01\xbcQ\xbb[INSERT INTO `crm_fields` VALUES ('bool','Boolean value (yes / no)','');\nINSERT INTO `crm_fields` VALUES ('email','E-mail input','');\nINSERT INTO `crm_fields` VALUES ('enum','Single option picker','');\nINSERT INTO `crm_fields` VALUES ('hidden','Hidden value','');\nINSERT INTO `crm_fields` VALUES ('stamp','Date/time input','');\nINSERT INTO `crm_fields` VALUES ('text','Text input','');\nINSERT INTO `crm_fields` VALUES ('textarea','Text input (multi-line)','');\nPK\x07\x08\xf8u|\xb9\xcc\x01\x00\x00\xcc\x01\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00migrations.sqlUT\x05\x00\x01\xbcQ\xbb[CREATE TABLE IF NOT EXISTS `migrations` (\n `project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',\n `filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',\n `statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',\n `status` varchar(16) NOT NULL COMMENT 'ok or full error message'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08~ 9=Z\x01\x00\x00Z\x01\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM\xe9\xe8\x9a\xeex\x06\x00\x00x\x06\x00\x00\x1a\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x0020180704080000.base.up.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM\xf8u|\xb9\xcc\x01\x00\x00\xcc\x01\x00\x00%\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xc9\x06\x00\x0020180704080001.crm_fields-data.up.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM~ 9=Z\x01\x00\x00Z\x01\x00\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xf1\x08\x00\x00migrations.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x05\x06\x00\x00\x00\x00\x03\x00\x03\x00\xf2\x00\x00\x00\x90\n\x00\x00\x00\x00"
|
||||
data := "PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00 \x0020180704080000.base.up.sqlUT\x05\x00\x01\xbcQ\xbb[CREATE TABLE `crm_content` (\n `id` bigint(20) unsigned NOT NULL,\n `module_id` bigint(20) unsigned NOT NULL,\n `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,\n `updated_at` datetime DEFAULT NULL,\n `archived_at` datetime DEFAULT NULL,\n `deleted_at` datetime DEFAULT NULL,\n PRIMARY KEY (`id`,`module_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_content_columns` (\n `content_id` bigint(20) NOT NULL,\n `column_name` varchar(255) NOT NULL,\n `column_value` text NOT NULL,\n PRIMARY KEY (`content_id`,`column_name`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_fields` (\n `field_type` varchar(16) NOT NULL COMMENT 'Short field type (string, boolean,...)',\n `field_name` varchar(255) NOT NULL COMMENT 'Description of field contents',\n `field_template` varchar(255) NOT NULL COMMENT 'HTML template file for field',\n PRIMARY KEY (`field_type`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_module` (\n `id` bigint(20) unsigned NOT NULL,\n `name` varchar(64) NOT NULL COMMENT 'The name of the module',\n `json` json NOT NULL COMMENT 'List of field definitions for the module',\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nCREATE TABLE `crm_module_form` (\n `module_id` bigint(20) unsigned NOT NULL,\n `place` tinyint(3) unsigned NOT NULL,\n `type` varchar(64) NOT NULL COMMENT 'The type of the form input field',\n `name` varchar(64) NOT NULL COMMENT 'The name of the field in the form',\n `title` varchar(255) NOT NULL COMMENT 'The label of the form input',\n `placeholder` varchar(255) NOT NULL COMMENT 'Placeholder text (if supported by input)',\n PRIMARY KEY (`module_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08\xe9\xe8\x9a\xeex\x06\x00\x00x\x06\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xdaeHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00 \x0020180704080001.crm_fields-data.up.sqlUT\x05\x00\x01\xbcQ\xbb[INSERT INTO `crm_fields` VALUES ('bool','Boolean value (yes / no)','');\nINSERT INTO `crm_fields` VALUES ('email','E-mail input','');\nINSERT INTO `crm_fields` VALUES ('enum','Single option picker','');\nINSERT INTO `crm_fields` VALUES ('hidden','Hidden value','');\nINSERT INTO `crm_fields` VALUES ('stamp','Date/time input','');\nINSERT INTO `crm_fields` VALUES ('text','Text input','');\nINSERT INTO `crm_fields` VALUES ('textarea','Text input (multi-line)','');\nPK\x07\x08\xf8u|\xb9\xcc\x01\x00\x00\xcc\x01\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\xc0kHM\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x00 \x00migrations.sqlUT\x05\x00\x01\xd9[\xbb[CREATE TABLE IF NOT EXISTS `migrations` (\n `project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',\n `filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',\n `statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',\n `status` varchar(16) NOT NULL COMMENT 'ok or full error message',\n PRIMARY KEY (`project`,`filename`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nPK\x07\x08%l\xb2\x16\x7f\x01\x00\x00\x7f\x01\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM\xe9\xe8\x9a\xeex\x06\x00\x00x\x06\x00\x00\x1a\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x0020180704080000.base.up.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xdaeHM\xf8u|\xb9\xcc\x01\x00\x00\xcc\x01\x00\x00%\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xc9\x06\x00\x0020180704080001.crm_fields-data.up.sqlUT\x05\x00\x01\xbcQ\xbb[PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\xc0kHM%l\xb2\x16\x7f\x01\x00\x00\x7f\x01\x00\x00\x0e\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xf1\x08\x00\x00migrations.sqlUT\x05\x00\x01\xd9[\xbb[PK\x05\x06\x00\x00\x00\x00\x03\x00\x03\x00\xf2\x00\x00\x00\xb5\n\x00\x00\x00\x00"
|
||||
fs.Register(data)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ CREATE TABLE IF NOT EXISTS `migrations` (
|
||||
`project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',
|
||||
`filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',
|
||||
`statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',
|
||||
`status` varchar(16) NOT NULL COMMENT 'ok or full error message'
|
||||
`status` varchar(16) NOT NULL COMMENT 'ok or full error message',
|
||||
PRIMARY KEY (`project`,`filename`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package db
|
||||
|
||||
type migration struct {
|
||||
Project string `db:"project"`
|
||||
Filename string `db:"filename"`
|
||||
StatementIndex int `db:"statement_index"`
|
||||
Status string `db:"status"`
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/titpetric/factory"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
migrate "github.com/crusttech/crust/crm/db"
|
||||
"github.com/crusttech/crust/crm/rest"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
)
|
||||
@@ -29,6 +30,7 @@ func Init() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// @todo: profiling as an external service?
|
||||
switch flags.db.Profiler {
|
||||
case "stdout":
|
||||
@@ -37,6 +39,11 @@ func Init() error {
|
||||
fmt.Println("No database query profiler selected")
|
||||
}
|
||||
|
||||
// migrate database schema
|
||||
if err := migrate.Migrate(db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// configure resputil options
|
||||
resputil.SetConfig(resputil.Options{
|
||||
Pretty: flags.http.Pretty,
|
||||
|
||||
+8
-13
@@ -24,13 +24,6 @@ func statements(contents []byte, err error) ([]string, error) {
|
||||
return regexp.MustCompilePOSIX(";$").Split(string(contents), -1), nil
|
||||
}
|
||||
|
||||
type migration struct {
|
||||
Project string
|
||||
Filename string
|
||||
StatementIndex int `db:"statement_index"`
|
||||
Status string
|
||||
}
|
||||
|
||||
func Migrate(db *factory.DB) error {
|
||||
statikFS, err := fs.New()
|
||||
if err != nil {
|
||||
@@ -89,14 +82,16 @@ func Migrate(db *factory.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := db.Transaction(up); err != nil {
|
||||
err := db.Transaction(up)
|
||||
if err != nil {
|
||||
status.Status = err.Error()
|
||||
if useLog {
|
||||
db.Replace("migrations", status)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if useLog {
|
||||
if err := db.Replace("migrations", status); err != nil {
|
||||
log.Println("replace failed", err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migrate("/migrations.sql", false); err != nil {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2,6 +2,7 @@ CREATE TABLE IF NOT EXISTS `migrations` (
|
||||
`project` varchar(16) NOT NULL COMMENT 'sam, crm, ...',
|
||||
`filename` varchar(255) NOT NULL COMMENT 'yyyymmddHHMMSS.sql',
|
||||
`statement_index` int(11) NOT NULL COMMENT 'Statement number from SQL file',
|
||||
`status` varchar(16) NOT NULL COMMENT 'ok or full error message'
|
||||
`status` varchar(16) NOT NULL COMMENT 'ok or full error message',
|
||||
PRIMARY KEY (`project`,`filename`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package db
|
||||
|
||||
type migration struct {
|
||||
Project string `db:"project"`
|
||||
Filename string `db:"filename"`
|
||||
StatementIndex int `db:"statement_index"`
|
||||
Status string `db:"status"`
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
authService "github.com/crusttech/crust/auth/service"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
migrate "github.com/crusttech/crust/sam/db"
|
||||
"github.com/crusttech/crust/sam/rest"
|
||||
samService "github.com/crusttech/crust/sam/service"
|
||||
"github.com/crusttech/crust/sam/websocket"
|
||||
@@ -33,6 +34,7 @@ func Init() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// @todo: profiling as an external service?
|
||||
switch flags.db.Profiler {
|
||||
case "stdout":
|
||||
@@ -41,6 +43,11 @@ func Init() error {
|
||||
fmt.Println("No database query profiler selected")
|
||||
}
|
||||
|
||||
// migrate database schema
|
||||
if err := migrate.Migrate(db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// configure resputil options
|
||||
resputil.SetConfig(resputil.Options{
|
||||
Pretty: flags.http.Pretty,
|
||||
|
||||
Reference in New Issue
Block a user