PLT-92 Adding server side versioning to the binary

Этот коммит содержится в:
=Corey Hulen
2015-09-16 17:37:11 -07:00
родитель e644b53b72
Коммит cef7a1aae4
13 изменённых файлов: 199 добавлений и 23 удалений

1
.gitignore поставляемый
Просмотреть файл

@@ -6,6 +6,7 @@ dist
npm-debug.log npm-debug.log
bundle*.js bundle*.js
model/version.go
# Compiled Object files, Static and Dynamic libs (Shared Objects) # Compiled Object files, Static and Dynamic libs (Shared Objects)

Просмотреть файл

@@ -3,6 +3,7 @@
GOPATH ?= $(GOPATH:) GOPATH ?= $(GOPATH:)
GOFLAGS ?= $(GOFLAGS:) GOFLAGS ?= $(GOFLAGS:)
BUILD_NUMBER ?= $(BUILD_NUMBER:) BUILD_NUMBER ?= $(BUILD_NUMBER:)
BUILD_DATE=`date +'%y.%m.%d %H:%M:%S'`
GO=$(GOPATH)/bin/godep go GO=$(GOPATH)/bin/godep go
ESLINT=node_modules/eslint/bin/eslint.js ESLINT=node_modules/eslint/bin/eslint.js
@@ -40,6 +41,9 @@ travis:
@echo Checking for style guide compliance @echo Checking for style guide compliance
cd web/react && $(ESLINT) --quiet components/* dispatcher/* pages/* stores/* utils/* cd web/react && $(ESLINT) --quiet components/* dispatcher/* pages/* stores/* utils/*
@sed -i'.bak' 's|_BUILD_NUMBER_|$(BUILD_NUMBER)|g' ./model/version.go
@sed -i'.bak' 's|_BUILD_DATE_|$(BUILD_DATE)|g' ./model/version.go
@$(GO) build $(GOFLAGS) ./... @$(GO) build $(GOFLAGS) ./...
@$(GO) install $(GOFLAGS) ./... @$(GO) install $(GOFLAGS) ./...
@@ -204,6 +208,9 @@ cleandb:
fi fi
dist: install dist: install
@sed -i'.bak' 's|_BUILD_NUMBER_|$(BUILD_NUMBER)|g' ./model/version.go
@sed -i'.bak' 's|_BUILD_DATE_|$(BUILD_DATE)|g' ./model/version.go
@$(GO) build $(GOFLAGS) -i ./... @$(GO) build $(GOFLAGS) -i ./...
@$(GO) install $(GOFLAGS) ./... @$(GO) install $(GOFLAGS) ./...

Просмотреть файл

@@ -125,7 +125,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.setSiteURL(protocol + "://" + r.Host) c.setSiteURL(protocol + "://" + r.Host)
w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId) w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId)
w.Header().Set(model.HEADER_VERSION_ID, utils.Cfg.ServiceSettings.Version+fmt.Sprintf(".%v", utils.CfgLastModified)) w.Header().Set(model.HEADER_VERSION_ID, fmt.Sprintf("%v.%v", model.GetFullVersion(), utils.CfgLastModified))
// Instruct the browser not to display us in an iframe for anti-clickjacking // Instruct the browser not to display us in an iframe for anti-clickjacking
if !h.isApi { if !h.isApi {

Просмотреть файл

@@ -23,6 +23,7 @@ import (
var flagCmdCreateTeam bool var flagCmdCreateTeam bool
var flagCmdCreateUser bool var flagCmdCreateUser bool
var flagCmdAssignRole bool var flagCmdAssignRole bool
var flagCmdVersion bool
var flagCmdResetPassword bool var flagCmdResetPassword bool
var flagConfigFile string var flagConfigFile string
var flagEmail string var flagEmail string
@@ -83,14 +84,16 @@ func parseCmds() {
flag.BoolVar(&flagCmdCreateTeam, "create_team", false, "") flag.BoolVar(&flagCmdCreateTeam, "create_team", false, "")
flag.BoolVar(&flagCmdCreateUser, "create_user", false, "") flag.BoolVar(&flagCmdCreateUser, "create_user", false, "")
flag.BoolVar(&flagCmdAssignRole, "assign_role", false, "") flag.BoolVar(&flagCmdAssignRole, "assign_role", false, "")
flag.BoolVar(&flagCmdVersion, "version", false, "")
flag.BoolVar(&flagCmdResetPassword, "reset_password", false, "") flag.BoolVar(&flagCmdResetPassword, "reset_password", false, "")
flag.Parse() flag.Parse()
flagRunCmds = flagCmdCreateTeam || flagCmdCreateUser || flagCmdAssignRole || flagCmdResetPassword flagRunCmds = flagCmdCreateTeam || flagCmdCreateUser || flagCmdAssignRole || flagCmdResetPassword || flagCmdVersion
} }
func runCmds() { func runCmds() {
cmdVersion()
cmdCreateTeam() cmdCreateTeam()
cmdCreateUser() cmdCreateUser()
cmdAssignRole() cmdAssignRole()
@@ -184,6 +187,16 @@ func cmdCreateUser() {
} }
} }
func cmdVersion() {
if flagCmdVersion {
fmt.Fprintln(os.Stderr, "Version: "+model.GetFullVersion())
fmt.Fprintln(os.Stderr, "Build Number: "+model.BUILD_NUMBER)
fmt.Fprintln(os.Stderr, "Build Date: "+model.BUILD_DATE)
os.Exit(0)
}
}
func cmdAssignRole() { func cmdAssignRole() {
if flagCmdAssignRole { if flagCmdAssignRole {
if len(flagTeamName) == 0 { if len(flagTeamName) == 0 {
@@ -298,6 +311,8 @@ Usage:
platform [options] platform [options]
-version Display the current version
-config="config.json" Path to the config file -config="config.json" Path to the config file
-email="user@example.com" Email address used in other commands -email="user@example.com" Email address used in other commands

Просмотреть файл

@@ -16,11 +16,6 @@ import (
"time" "time"
) )
const (
// Also change web/react/stores/browser_store.jsx BROWSER_STORE_VERSION
ETAG_ROOT_VERSION = "12"
)
type StringMap map[string]string type StringMap map[string]string
type StringArray []string type StringArray []string
type EncryptStringMap map[string]string type EncryptStringMap map[string]string
@@ -235,7 +230,7 @@ func IsValidAlphaNum(s string, allowUnderscores bool) bool {
func Etag(parts ...interface{}) string { func Etag(parts ...interface{}) string {
etag := ETAG_ROOT_VERSION etag := GetFullVersion()
for _, part := range parts { for _, part := range parts {
etag += fmt.Sprintf(".%v", part) etag += fmt.Sprintf(".%v", part)

78
model/version.go Обычный файл
Просмотреть файл

@@ -0,0 +1,78 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"fmt"
"strconv"
"strings"
)
const (
VERSION_MAJOR = 0
VERSION_MINOR = 7
VERSION_PATCH = 0
BUILD_NUMBER = "_BUILD_NUMBER_"
BUILD_DATE = "_BUILD_DATE_"
)
func GetFullVersion() string {
return fmt.Sprintf("%v.%v.%v", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
}
func SplitVersion(version string) (int64, int64, int64) {
parts := strings.Split(version, ".")
major := int64(0)
minor := int64(0)
patch := int64(0)
if len(parts) > 0 {
major, _ = strconv.ParseInt(parts[0], 10, 64)
}
if len(parts) > 1 {
minor, _ = strconv.ParseInt(parts[1], 10, 64)
}
if len(parts) > 2 {
patch, _ = strconv.ParseInt(parts[2], 10, 64)
}
return major, minor, patch
}
func GetPreviousVersion(version string) (int64, int64) {
major, minor, _ := SplitVersion(version)
if minor == 0 {
major = major - 1
minor = 9
} else {
minor = minor - 1
}
return major, minor
}
func IsCurrentVersion(versionToCheck string) bool {
toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
if toCheckMajor == VERSION_MAJOR && toCheckMinor == VERSION_MINOR {
return true
} else {
return false
}
}
func IsLastVersion(versionToCheck string) bool {
toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
prevMajor, prevMinor := GetPreviousVersion(GetFullVersion())
if toCheckMajor == prevMajor && toCheckMinor == prevMinor {
return true
} else {
return false
}
}

72
model/version_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,72 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"fmt"
"testing"
)
func TestVersion(t *testing.T) {
GetFullVersion()
major1, minor1, patch1 := SplitVersion("junk")
if major1 != 0 || minor1 != 0 || patch1 != 0 {
t.Fatal()
}
major2, minor2, patch2 := SplitVersion("1.2.3")
if major2 != 1 || minor2 != 2 || patch2 != 3 {
t.Fatal()
}
major3, minor3, patch3 := SplitVersion("1.2")
if major3 != 1 || minor3 != 2 || patch3 != 0 {
t.Fatal()
}
major4, minor4, patch4 := SplitVersion("1")
if major4 != 1 || minor4 != 0 || patch4 != 0 {
t.Fatal()
}
major5, minor5, patch5 := SplitVersion("1.2.3.junkgoeswhere")
if major5 != 1 || minor5 != 2 || patch5 != 3 {
t.Fatal()
}
if IsLastVersion(GetFullVersion()) {
t.Fatal()
}
if !IsLastVersion(fmt.Sprintf("%v.%v.%v", VERSION_MAJOR, VERSION_MINOR-1, VERSION_PATCH)) {
t.Fatal()
}
// pacth should not affect current version check
if !IsLastVersion(fmt.Sprintf("%v.%v.%v", VERSION_MAJOR, VERSION_MINOR-1, VERSION_PATCH+1)) {
t.Fatal()
}
if IsLastVersion(fmt.Sprintf("%v.%v.%v", VERSION_MAJOR, VERSION_MINOR+1, VERSION_PATCH)) {
t.Fatal()
}
if !IsCurrentVersion(fmt.Sprintf("%v.%v.%v", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)) {
t.Fatal()
}
// pacth should not affect current version check
if !IsCurrentVersion(fmt.Sprintf("%v.%v.%v", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH+1)) {
t.Fatal()
}
if IsCurrentVersion(fmt.Sprintf("%v.%v.%v", VERSION_MAJOR, VERSION_MINOR+1, VERSION_PATCH)) {
t.Fatal()
}
if IsCurrentVersion(fmt.Sprintf("%v.%v.%v", VERSION_MAJOR+1, VERSION_MINOR, VERSION_PATCH)) {
t.Fatal()
}
}

Просмотреть файл

@@ -196,9 +196,9 @@ func (s SqlPostStore) GetEtag(channelId string) StoreChannel {
var et etagPosts var et etagPosts
err := s.GetReplica().SelectOne(&et, "SELECT Id, UpdateAt FROM Posts WHERE ChannelId = :ChannelId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"ChannelId": channelId}) err := s.GetReplica().SelectOne(&et, "SELECT Id, UpdateAt FROM Posts WHERE ChannelId = :ChannelId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"ChannelId": channelId})
if err != nil { if err != nil {
result.Data = fmt.Sprintf("%v.0.%v", model.ETAG_ROOT_VERSION, model.GetMillis()) result.Data = fmt.Sprintf("%v.0.%v", model.GetFullVersion(), model.GetMillis())
} else { } else {
result.Data = fmt.Sprintf("%v.%v.%v", model.ETAG_ROOT_VERSION, et.Id, et.UpdateAt) result.Data = fmt.Sprintf("%v.%v.%v", model.GetFullVersion(), et.Id, et.UpdateAt)
} }
storeChannel <- result storeChannel <- result

Просмотреть файл

@@ -37,14 +37,14 @@ func TestPostStoreGet(t *testing.T) {
o1.Message = "a" + model.NewId() + "b" o1.Message = "a" + model.NewId() + "b"
etag1 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string) etag1 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string)
if strings.Index(etag1, model.ETAG_ROOT_VERSION+".0.") != 0 { if strings.Index(etag1, model.GetFullVersion()+".0.") != 0 {
t.Fatal("Invalid Etag") t.Fatal("Invalid Etag")
} }
o1 = (<-store.Post().Save(o1)).Data.(*model.Post) o1 = (<-store.Post().Save(o1)).Data.(*model.Post)
etag2 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string) etag2 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string)
if strings.Index(etag2, model.ETAG_ROOT_VERSION+"."+o1.Id) != 0 { if strings.Index(etag2, model.GetFullVersion()+"."+o1.Id) != 0 {
t.Fatal("Invalid Etag") t.Fatal("Invalid Etag")
} }
@@ -136,7 +136,7 @@ func TestPostStoreDelete(t *testing.T) {
o1.Message = "a" + model.NewId() + "b" o1.Message = "a" + model.NewId() + "b"
etag1 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string) etag1 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string)
if strings.Index(etag1, model.ETAG_ROOT_VERSION+".0.") != 0 { if strings.Index(etag1, model.GetFullVersion()+".0.") != 0 {
t.Fatal("Invalid Etag") t.Fatal("Invalid Etag")
} }
@@ -160,7 +160,7 @@ func TestPostStoreDelete(t *testing.T) {
} }
etag2 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string) etag2 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string)
if strings.Index(etag2, model.ETAG_ROOT_VERSION+"."+o1.Id) != 0 { if strings.Index(etag2, model.GetFullVersion()+"."+o1.Id) != 0 {
t.Fatal("Invalid Etag") t.Fatal("Invalid Etag")
} }
} }

Просмотреть файл

@@ -56,6 +56,8 @@ func NewSqlStore() Store {
utils.Cfg.SqlSettings.Trace) utils.Cfg.SqlSettings.Trace)
} }
//version := sqlStore.GetCurrentSchemaVersion()
// Temporary upgrade code, remove after 0.8.0 release // Temporary upgrade code, remove after 0.8.0 release
if sqlStore.DoesColumnExist("Sessions", "AltId") { if sqlStore.DoesColumnExist("Sessions", "AltId") {
sqlStore.GetMaster().Exec("DROP TABLE IF EXISTS Sessions") sqlStore.GetMaster().Exec("DROP TABLE IF EXISTS Sessions")
@@ -131,6 +133,11 @@ func setupConnection(con_type string, driver string, dataSource string, maxIdle
return dbmap return dbmap
} }
func (ss SqlStore) GetCurrentSchemaVersion() string {
version, _ := ss.GetMaster().SelectStr("SELECT PropVal FROM MattermostSystem WHERE PropName='SchemaVersion'")
return version
}
func (ss SqlStore) DoesColumnExist(tableName string, columnName string) bool { func (ss SqlStore) DoesColumnExist(tableName string, columnName string) bool {
if utils.Cfg.SqlSettings.DriverName == "postgres" { if utils.Cfg.SqlSettings.DriverName == "postgres" {
count, err := ss.GetMaster().SelectInt( count, err := ss.GetMaster().SelectInt(

Просмотреть файл

@@ -325,9 +325,9 @@ func (s SqlUserStore) GetEtagForProfiles(teamId string) StoreChannel {
updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users WHERE TeamId = :TeamId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"TeamId": teamId}) updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users WHERE TeamId = :TeamId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"TeamId": teamId})
if err != nil { if err != nil {
result.Data = fmt.Sprintf("%v.%v", model.ETAG_ROOT_VERSION, model.GetMillis()) result.Data = fmt.Sprintf("%v.%v", model.GetFullVersion(), model.GetMillis())
} else { } else {
result.Data = fmt.Sprintf("%v.%v", model.ETAG_ROOT_VERSION, updateAt) result.Data = fmt.Sprintf("%v.%v", model.GetFullVersion(), updateAt)
} }
storeChannel <- result storeChannel <- result

Просмотреть файл

@@ -11,6 +11,8 @@ import (
"strconv" "strconv"
l4g "code.google.com/p/log4go" l4g "code.google.com/p/log4go"
"github.com/mattermost/platform/model"
) )
const ( const (
@@ -26,7 +28,6 @@ type ServiceSettings struct {
AllowTesting bool AllowTesting bool
UseSSL bool UseSSL bool
Port string Port string
Version string
InviteSalt string InviteSalt string
PublicLinkSalt string PublicLinkSalt string
ResetSalt string ResetSalt string
@@ -275,7 +276,10 @@ func getSanitizeOptions(c *Config) map[string]bool {
func getClientProperties(c *Config) map[string]string { func getClientProperties(c *Config) map[string]string {
props := make(map[string]string) props := make(map[string]string)
props["Version"] = c.ServiceSettings.Version props["Version"] = model.GetFullVersion()
props["BuildNumber"] = model.BUILD_NUMBER
props["BuildDate"] = model.BUILD_DATE
props["SiteName"] = c.ServiceSettings.SiteName props["SiteName"] = c.ServiceSettings.SiteName
props["ByPassEmail"] = strconv.FormatBool(c.EmailSettings.ByPassEmail) props["ByPassEmail"] = strconv.FormatBool(c.EmailSettings.ByPassEmail)
props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail

Просмотреть файл

@@ -9,9 +9,6 @@ function getPrefix() {
return UserStore.getCurrentId() + '_'; return UserStore.getCurrentId() + '_';
} }
// Also change model/utils.go ETAG_ROOT_VERSION
var BROWSER_STORE_VERSION = '.5';
class BrowserStoreClass { class BrowserStoreClass {
constructor() { constructor() {
this.getItem = this.getItem.bind(this); this.getItem = this.getItem.bind(this);
@@ -25,9 +22,9 @@ class BrowserStoreClass {
this.isLocalStorageSupported = this.isLocalStorageSupported.bind(this); this.isLocalStorageSupported = this.isLocalStorageSupported.bind(this);
var currentVersion = localStorage.getItem('local_storage_version'); var currentVersion = localStorage.getItem('local_storage_version');
if (currentVersion !== BROWSER_STORE_VERSION) { if (currentVersion !== global.window.config.Version) {
this.clear(); this.clear();
localStorage.setItem('local_storage_version', BROWSER_STORE_VERSION); localStorage.setItem('local_storage_version', global.window.config.Version);
} }
} }