From bb103e87239e6789b42eb4ceaab45f6cf49adb2e Mon Sep 17 00:00:00 2001
From: Peter Smit <peter@smitmail.eu>
Date: Thu, 22 Jan 2015 14:49:52 +0200
Subject: [PATCH 1/3] Create db migrations framework

---
 models/migrations/migrations.go | 47 +++++++++++++++++++++++++++++++++
 models/models.go                |  6 +++++
 2 files changed, 53 insertions(+)
 create mode 100644 models/migrations/migrations.go

diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
new file mode 100644
index 0000000000..0b52708172
--- /dev/null
+++ b/models/migrations/migrations.go
@@ -0,0 +1,47 @@
+package migrations
+
+import (
+	"errors"
+	"github.com/go-xorm/xorm"
+)
+
+type migration func(*xorm.Engine) error
+
+// The version table. Should have only one row with id==1
+type Version struct {
+	Id      int64 `xorm:"pk"`
+	Version int64
+}
+
+// This is a sequence of migrations. Add new migrations to the bottom of the list.
+// If you want to "retire" a migration, replace it with "expiredMigration"
+var migrations = []migration{}
+
+// Migrate database to current version
+func Migrate(x *xorm.Engine) error {
+	x.Sync(new(Version))
+
+	currentVersion := &Version{Id: 1}
+	has, err := x.Get(currentVersion)
+	if err != nil {
+		return err
+	}
+	if !has {
+		_, err = x.InsertOne(currentVersion)
+	}
+
+	v := currentVersion.Version
+
+	for i, migration := range migrations[v:] {
+		if err = migration(x); err != nil {
+			return err
+		}
+		currentVersion.Version = v + int64(i) + 1
+		x.Id(1).Update(currentVersion)
+	}
+	return nil
+}
+
+func expiredMigration(x *xorm.Engine) error {
+	return errors.New("You are migrating from a too old gogs version")
+}
diff --git a/models/models.go b/models/models.go
index cf2124417a..55e7bf5822 100644
--- a/models/models.go
+++ b/models/models.go
@@ -15,6 +15,7 @@ import (
 	"github.com/go-xorm/xorm"
 	_ "github.com/lib/pq"
 
+	"github.com/gogits/gogs/models/migrations"
 	"github.com/gogits/gogs/modules/setting"
 )
 
@@ -131,6 +132,11 @@ func NewEngine() (err error) {
 	if err = SetEngine(); err != nil {
 		return err
 	}
+
+	if err = migrations.Migrate(x); err != nil {
+		return err
+	}
+
 	if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil {
 		return fmt.Errorf("sync database struct error: %v\n", err)
 	}

From 2a70d6b7235a124027ebc446d8559b4596cb6dcd Mon Sep 17 00:00:00 2001
From: Peter Smit <peter@smitmail.eu>
Date: Thu, 22 Jan 2015 14:56:50 +0200
Subject: [PATCH 2/3] Clean up migrations code

---
 models/migrations/migrations.go | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 0b52708172..e51bc3c876 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -2,6 +2,7 @@ package migrations
 
 import (
 	"errors"
+
 	"github.com/go-xorm/xorm"
 )
 
@@ -9,7 +10,7 @@ type migration func(*xorm.Engine) error
 
 // The version table. Should have only one row with id==1
 type Version struct {
-	Id      int64 `xorm:"pk"`
+	Id      int64
 	Version int64
 }
 
@@ -25,9 +26,10 @@ func Migrate(x *xorm.Engine) error {
 	has, err := x.Get(currentVersion)
 	if err != nil {
 		return err
-	}
-	if !has {
-		_, err = x.InsertOne(currentVersion)
+	} else if !has {
+		if _, err = x.InsertOne(currentVersion); err != nil {
+			return err
+		}
 	}
 
 	v := currentVersion.Version

From 4ef32454138a40c8b3cc5334c8980e71bd431825 Mon Sep 17 00:00:00 2001
From: Peter Smit <peter@smitmail.eu>
Date: Thu, 22 Jan 2015 15:01:45 +0200
Subject: [PATCH 3/3] Migration code: errors are not to be forgotten

---
 models/migrations/migrations.go | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index e51bc3c876..3586e5d0b6 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -20,7 +20,9 @@ var migrations = []migration{}
 
 // Migrate database to current version
 func Migrate(x *xorm.Engine) error {
-	x.Sync(new(Version))
+	if err := x.Sync(new(Version)); err != nil {
+		return err
+	}
 
 	currentVersion := &Version{Id: 1}
 	has, err := x.Get(currentVersion)
@@ -39,7 +41,9 @@ func Migrate(x *xorm.Engine) error {
 			return err
 		}
 		currentVersion.Version = v + int64(i) + 1
-		x.Id(1).Update(currentVersion)
+		if _, err = x.Id(1).Update(currentVersion); err != nil {
+			return err
+		}
 	}
 	return nil
 }