database migrations - gh updates - 29.6

pull/15/head
Hunter Long 2018-07-05 20:01:03 -07:00
parent 1f2991e765
commit 5f2037a2cd
12 changed files with 183 additions and 49 deletions

View File

@ -18,7 +18,7 @@ services:
env: env:
global: global:
- VERSION=0.29.5 - VERSION=0.29.6
- DB_HOST=localhost - DB_HOST=localhost
- DB_USER=travis - DB_USER=travis
- DB_PASS= - DB_PASS=

View File

@ -1,6 +1,6 @@
FROM alpine:latest FROM alpine:latest
ENV VERSION=v0.29.5 ENV VERSION=v0.29.6
RUN apk --no-cache add libstdc++ ca-certificates RUN apk --no-cache add libstdc++ ca-certificates
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \ RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \

120
cli.go
View File

@ -1,13 +1,17 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/hunterlong/statup/core" "github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/plugin" "github.com/hunterlong/statup/plugin"
"github.com/hunterlong/statup/types" "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"io/ioutil"
"math/rand" "math/rand"
"net/http"
"os"
"strings" "strings"
"time" "time"
"upper.io/db.v3/sqlite" "upper.io/db.v3/sqlite"
@ -27,8 +31,18 @@ func CatchCLI(args []string) {
core.CreateAllAssets() core.CreateAllAssets()
case "sass": case "sass":
core.CompileSASS() core.CompileSASS()
case "api": case "update":
HelpEcho() gitCurrent, err := CheckGithubUpdates()
if err != nil {
fmt.Println(err)
os.Exit(2)
}
fmt.Printf("Statup Version: v%v\nLatest Version: %v\n", VERSION, gitCurrent.TagName)
if VERSION != gitCurrent.TagName[1:] {
fmt.Printf("You don't have the latest version v%v!\nDownload the latest release at: https://github.com/hunterlong/statup\n", gitCurrent.TagName[1:])
} else {
fmt.Printf("You have the latest version of Statup!\n")
}
case "test": case "test":
cmd := args[2] cmd := args[2]
switch cmd { switch cmd {
@ -52,8 +66,6 @@ func CatchCLI(args []string) {
utils.Log(1, "Exported Statup index page: 'index.html'") utils.Log(1, "Exported Statup index page: 'index.html'")
case "help": case "help":
HelpEcho() HelpEcho()
case "update":
fmt.Println("Sorry updating isn't available yet!")
case "run": case "run":
utils.Log(1, "Running 1 time and saving to database...") utils.Log(1, "Running 1 time and saving to database...")
RunOnce() RunOnce()
@ -72,6 +84,10 @@ func CatchCLI(args []string) {
} }
} }
func CheckUpdates() {
}
func RunOnce() { func RunOnce() {
var err error var err error
core.Configs, err = core.LoadConfig() core.Configs, err = core.LoadConfig()
@ -265,3 +281,99 @@ func FakeSeed(plug plugin.PluginActions) {
fmt.Println("Seeding example data is complete, running Plugin Tests") fmt.Println("Seeding example data is complete, running Plugin Tests")
} }
func CheckGithubUpdates() (GithubResponse, error) {
var gitResp GithubResponse
response, err := http.Get("https://api.github.com/repos/hunterlong/statup/releases/latest")
if err != nil {
return GithubResponse{}, err
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
return GithubResponse{}, err
}
err = json.Unmarshal(contents, &gitResp)
return gitResp, err
}
return gitResp, err
}
type GithubResponse struct {
URL string `json:"url"`
AssetsURL string `json:"assets_url"`
UploadURL string `json:"upload_url"`
HTMLURL string `json:"html_url"`
ID int `json:"id"`
NodeID string `json:"node_id"`
TagName string `json:"tag_name"`
TargetCommitish string `json:"target_commitish"`
Name string `json:"name"`
Draft bool `json:"draft"`
Author GitAuthor `json:"author"`
Prerelease bool `json:"prerelease"`
CreatedAt time.Time `json:"created_at"`
PublishedAt time.Time `json:"published_at"`
Assets []GitAssets `json:"assets"`
TarballURL string `json:"tarball_url"`
ZipballURL string `json:"zipball_url"`
Body string `json:"body"`
}
type GitAuthor struct {
Login string `json:"login"`
ID int `json:"id"`
NodeID string `json:"node_id"`
AvatarURL string `json:"avatar_url"`
GravatarID string `json:"gravatar_id"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
FollowersURL string `json:"followers_url"`
FollowingURL string `json:"following_url"`
GistsURL string `json:"gists_url"`
StarredURL string `json:"starred_url"`
SubscriptionsURL string `json:"subscriptions_url"`
OrganizationsURL string `json:"organizations_url"`
ReposURL string `json:"repos_url"`
EventsURL string `json:"events_url"`
ReceivedEventsURL string `json:"received_events_url"`
Type string `json:"type"`
SiteAdmin bool `json:"site_admin"`
}
type GitAssets struct {
URL string `json:"url"`
ID int `json:"id"`
NodeID string `json:"node_id"`
Name string `json:"name"`
Label string `json:"label"`
Uploader GitUploader `json:"uploader"`
ContentType string `json:"content_type"`
State string `json:"state"`
Size int `json:"size"`
DownloadCount int `json:"download_count"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
BrowserDownloadURL string `json:"browser_download_url"`
}
type GitUploader struct {
Login string `json:"login"`
ID int `json:"id"`
NodeID string `json:"node_id"`
AvatarURL string `json:"avatar_url"`
GravatarID string `json:"gravatar_id"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
FollowersURL string `json:"followers_url"`
FollowingURL string `json:"following_url"`
GistsURL string `json:"gists_url"`
StarredURL string `json:"starred_url"`
SubscriptionsURL string `json:"subscriptions_url"`
OrganizationsURL string `json:"organizations_url"`
ReposURL string `json:"repos_url"`
EventsURL string `json:"events_url"`
ReceivedEventsURL string `json:"received_events_url"`
Type string `json:"type"`
SiteAdmin bool `json:"site_admin"`
}

View File

@ -20,6 +20,8 @@ type Core struct {
Footer string `db:"footer" json:"-"` Footer string `db:"footer" json:"-"`
Domain string `db:"domain" json:"domain,omitempty"` Domain string `db:"domain" json:"domain,omitempty"`
Version string `db:"version" json:"version,omitempty"` Version string `db:"version" json:"version,omitempty"`
MigrationId int64 `db:"migration_id" json:"-"`
UseCdn bool `db:"use_cdn" json:"-"`
Services []*Service `json:"services,omitempty"` Services []*Service `json:"services,omitempty"`
Plugins []plugin.Info Plugins []plugin.Info
Repos []PluginJSON Repos []PluginJSON
@ -103,6 +105,15 @@ func (c Core) AllOnline() bool {
return true return true
} }
func SelectLastMigration() (int64, error) {
var c *Core
err := DbSession.Collection("core").Find().One(&c)
if err != nil {
return 0, err
}
return c.MigrationId, err
}
func SelectCore() (*Core, error) { func SelectCore() (*Core, error) {
var c *Core var c *Core
err := DbSession.Collection("core").Find().One(&c) err := DbSession.Collection("core").Find().One(&c)

View File

@ -20,6 +20,7 @@ var (
postgresSettings postgresql.ConnectionURL postgresSettings postgresql.ConnectionURL
mysqlSettings mysql.ConnectionURL mysqlSettings mysql.ConnectionURL
DbSession sqlbuilder.Database DbSession sqlbuilder.Database
currentMigration int64
) )
type DbConfig types.DbConfig type DbConfig types.DbConfig
@ -66,7 +67,10 @@ func DbConnection(dbType string) error {
return err return err
} }
} }
//dbSession.SetLogging(true) err = DbSession.Ping()
if err == nil {
utils.Log(1, fmt.Sprintf("Database connection to '%v' was successful.", DbSession.Name()))
}
return err return err
} }
@ -122,6 +126,7 @@ func (c *DbConfig) Save() error {
ApiKey: utils.NewSHA1Hash(9), ApiKey: utils.NewSHA1Hash(9),
ApiSecret: utils.NewSHA1Hash(16), ApiSecret: utils.NewSHA1Hash(16),
Domain: c.Domain, Domain: c.Domain,
MigrationId: time.Now().Unix(),
} }
col := DbSession.Collection("core") col := DbSession.Collection("core")
_, err = col.Insert(newCore) _, err = col.Insert(newCore)
@ -135,78 +140,65 @@ func (c *DbConfig) Save() error {
return err return err
} }
func versionSplit(v string) (int64, int64, int64) { func versionHigher(migrate int64) bool {
currSplit := strings.Split(v, ".") if CoreApp.MigrationId < migrate {
if len(currSplit) < 2 {
return 9999, 9999, 9999
}
var major, mid, minor string
if len(currSplit) == 3 {
major = currSplit[0]
mid = currSplit[1]
minor = currSplit[2]
return utils.StringInt(major), utils.StringInt(mid), utils.StringInt(minor)
}
major = currSplit[0]
mid = currSplit[1]
return utils.StringInt(major), utils.StringInt(mid), 0
}
func versionHigher(migrate string) bool {
cM, cMi, cMn := versionSplit(CoreApp.Version)
mM, mMi, mMn := versionSplit(migrate)
if mM > cM {
return true
}
if mMi > cMi {
return true
}
if mMn > cMn {
return true return true
} }
return false return false
} }
func reverseSlice(s []string) []string {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
func RunDatabaseUpgrades() error { func RunDatabaseUpgrades() error {
var err error var err error
utils.Log(1, fmt.Sprintf("Checking Database Upgrades from v%v in '%v_upgrade.sql'...", CoreApp.Version, CoreApp.DbConnection)) currentMigration, err = SelectLastMigration()
utils.Log(1, fmt.Sprintf("Checking for Database Upgrades since #%v", currentMigration))
upgrade, _ := SqlBox.String(CoreApp.DbConnection + "_upgrade.sql") upgrade, _ := SqlBox.String(CoreApp.DbConnection + "_upgrade.sql")
// parse db version and upgrade file // parse db version and upgrade file
ups := strings.Split(upgrade, "=========================================== ") ups := strings.Split(upgrade, "=========================================== ")
ups = reverseSlice(ups)
var ran int var ran int
var lastMigration int64
for _, v := range ups { for _, v := range ups {
if len(v) == 0 { if len(v) == 0 {
continue continue
} }
vers := strings.Split(v, "\n") vers := strings.Split(v, "\n")
version := vers[0] lastMigration = utils.StringInt(vers[0])
data := vers[1:] data := vers[1:]
//fmt.Printf("Checking Migration from v%v to v%v - %v\n", CoreApp.Version, version, versionHigher(version)) //fmt.Printf("Checking Migration from v%v to v%v - %v\n", CoreApp.Version, version, versionHigher(version))
if !versionHigher(version) { if currentMigration >= lastMigration {
//fmt.Printf("Already up-to-date with v%v\n", version)
continue continue
} }
fmt.Printf("Migration Database from v%v to v%v\n", CoreApp.Version, version) utils.Log(1, fmt.Sprintf("Migrating Database from #%v to #%v", currentMigration, lastMigration))
for _, m := range data { for _, m := range data {
if m == "" { if m == "" {
continue continue
} }
fmt.Printf("Running Migration: %v\n", m) utils.Log(1, fmt.Sprintf("Running Query: %v", m))
_, err := DbSession.Exec(db.Raw(m + ";")) _, err := DbSession.Exec(db.Raw(m + ";"))
ran++
if err != nil { if err != nil {
utils.Log(2, err) utils.Log(2, err)
continue continue
} }
ran++
CoreApp.Version = m
} }
currentMigration = lastMigration
} }
if ran > 0 { if ran > 0 {
utils.Log(1, fmt.Sprintf("Database Upgraded, %v query ran", ran)) utils.Log(1, fmt.Sprintf("Database Upgraded %v queries ran, current #%v", ran, currentMigration))
CoreApp.Update()
CoreApp, err = SelectCore() CoreApp, err = SelectCore()
} else { if err != nil {
utils.Log(1, fmt.Sprintf("Database is already up-to-date, latest v%v", CoreApp.Version)) panic(err)
}
CoreApp.MigrationId = currentMigration
CoreApp.Update()
} }
return err return err
} }

View File

@ -65,6 +65,7 @@ func mainProcess() {
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
} }
core.RunDatabaseUpgrades() core.RunDatabaseUpgrades()
core.InitApp() core.InitApp()

View File

@ -7,7 +7,9 @@ CREATE TABLE core (
style text, style text,
footer text, footer text,
domain text, domain text,
version VARCHAR(50) version VARCHAR(50),
migration_id INT(6) NOT NULL DEFAULT 0,
use_cdn BOOL NOT NULL DEFAULT '0'
); );
CREATE TABLE users ( CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,

View File

@ -0,0 +1,4 @@
=========================================== 1530841150
ALTER TABLE core ADD COLUMN use_cdn BOOL NOT NULL DEFAULT '0';
=========================================== 1
ALTER TABLE core ADD COLUMN migration_id INT(6) NOT NULL DEFAULT 0;

View File

@ -7,7 +7,9 @@ CREATE TABLE core (
style text, style text,
footer text, footer text,
domain text, domain text,
version text version text,
migration_id integer default 0,
use_cdn bool default false
); );
CREATE TABLE users ( CREATE TABLE users (

View File

@ -0,0 +1,4 @@
=========================================== 1530841150
ALTER TABLE core ADD COLUMN use_cdn bool DEFAULT FALSE;
=========================================== 1
ALTER TABLE core ADD COLUMN migration_id integer default 0 NOT NULL;

View File

@ -7,7 +7,9 @@ CREATE TABLE core (
style text, style text,
footer text, footer text,
domain text, domain text,
version text version text,
migration_id integer default 0,
use_cdn bool default false
); );
CREATE TABLE users ( CREATE TABLE users (

View File

@ -0,0 +1,4 @@
=========================================== 1530841150
ALTER TABLE core ADD COLUMN use_cdn bool DEFAULT FALSE;
=========================================== 1
ALTER TABLE core ADD COLUMN migration_id integer NOT NULL DEFAULT 0;