Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

👻 refactor migrations #497

Merged
merged 1 commit into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 5 additions & 36 deletions hack/next-migration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ importRoot="github.com/konveyor/tackle2-hub/migration"
#
# Determine migration versions.
#
migrations=($(find ${root} -maxdepth 1 -type d -name 'v*' -printf '%f\n' | sort))
migrations=($(find ${root} -maxdepth 1 -type d -name 'v*' -printf '%f\n' | cut -c2-10 | sort -n))
current=${migrations[-1]}
n=${current#"v"}

Expand All @@ -31,9 +31,9 @@ echo "Current: ${currentDir}"
echo "Next: ${nextDir}"

#
# Create directores.
# New package.
#
mkdir -p ${nextDir}/model
mkdir -p ${nextDir}

#
# Build migrate.go
Expand Down Expand Up @@ -66,40 +66,9 @@ EOF
echo "${migrate}" > ${file}

#
# Build model/pkg.go
# Copy model
#
file=${nextDir}/model/pkg.go
pkg=$(cat << EOF
package model

import "${importRoot}/${current}/model"

//
// JSON field (data) type.
type JSON = []byte
EOF
)

echo "${pkg}" > ${file}

echo "" >> ${file}
models=$(grep "type" model/pkg.go | grep "model")
echo "${models}" >> ${file}
echo -n "
//
// All builds all models.
// Models are enumerated such that each are listed after
// all the other models on which they may depend.
func All() []interface{} {
return []interface{}{
" >> ${file}
models=$(grep "{}," ${currentDir}/model/pkg.go)
echo "${models}" | while read m
do
echo -e "\t\t${m}" >> ${file}
done
echo -e "\t}" >> ${file}
echo "}" >> ${file}
cp -r ${currentDir}/model ${nextDir}

#
# Register new migration.
Expand Down
71 changes: 70 additions & 1 deletion migration/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import (
liberr "github.com/jortel/go-utils/error"
"github.com/konveyor/tackle2-hub/database"
"github.com/konveyor/tackle2-hub/model"
"github.com/konveyor/tackle2-hub/nas"
"gorm.io/gorm"
"os"
"path"
"regexp"
"strconv"
"strings"
)

//
Expand Down Expand Up @@ -80,7 +86,11 @@ func Migrate(migrations []Migration) (err error) {
err = liberr.Wrap(err, "version", ver)
return
}

err = writeSchema(db, ver)
if err != nil {
err = liberr.Wrap(err, "version", ver)
return
}
err = database.Close(db)
if err != nil {
err = liberr.Wrap(err, "version", ver)
Expand Down Expand Up @@ -134,3 +144,62 @@ func autoMigrate(db *gorm.DB, models []interface{}) (err error) {
}
return
}

//
// writeSchema - writes the migrated schema to a file.
func writeSchema(db *gorm.DB, version int) (err error) {
var list []struct {
Type string `gorm:"column:type"`
Name string `gorm:"column:name"`
Table string `gorm:"column:tbl_name"`
RootPage int `gorm:"column:rootpage"`
SQL string `gorm:"column:sql"`
}
db = db.Table("sqlite_schema")
db = db.Order("1, 2")
err = db.Find(&list).Error
if err != nil {
return
}
dir := path.Join(
path.Dir(Settings.Hub.DB.Path),
"migration")
err = nas.MkDir(dir, 0755)
f, err := os.Create(path.Join(dir, strconv.Itoa(version)))
if err != nil {
return
}
defer func() {
_ = f.Close()
}()
pattern := regexp.MustCompile(`[,()]`)
SQL := func(in string) (out string) {
indent := "\n "
for {
m := pattern.FindStringIndex(in)
if m == nil {
out += in
break
}
out += indent
out += in[:m[0]]
out += indent
out += in[m[0]:m[1]]
in = in[m[1]:]
}
return
}
for _, m := range list {
s := strings.Join([]string{
m.Type,
m.Name,
m.Table,
SQL(m.SQL),
}, "|")
_, err = f.WriteString(s + "\n")
if err != nil {
return
}
}
return
}
87 changes: 87 additions & 0 deletions migration/v10/model/analysis.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package model

import "gorm.io/gorm"

//
// Analysis report.
type Analysis struct {
Expand Down Expand Up @@ -76,3 +78,88 @@ type ArchivedIssue struct {
Effort int `json:"effort"`
Incidents int `json:"incidents"`
}

//
// RuleSet - Analysis ruleset.
type RuleSet struct {
Model
UUID *string `gorm:"uniqueIndex"`
Kind string
Name string `gorm:"uniqueIndex;not null"`
Description string
Repository JSON `gorm:"type:json"`
IdentityID *uint `gorm:"index"`
Identity *Identity
Rules []Rule `gorm:"constraint:OnDelete:CASCADE"`
DependsOn []RuleSet `gorm:"many2many:RuleSetDependencies;constraint:OnDelete:CASCADE"`
}

func (r *RuleSet) Builtin() bool {
return r.UUID != nil
}

//
// BeforeUpdate hook to avoid cyclic dependencies.
func (r *RuleSet) BeforeUpdate(db *gorm.DB) (err error) {
seen := make(map[uint]bool)
var nextDeps []RuleSet
var nextRuleSetIDs []uint
for _, dep := range r.DependsOn {
nextRuleSetIDs = append(nextRuleSetIDs, dep.ID)
}
for len(nextRuleSetIDs) != 0 {
result := db.Preload("DependsOn").Where("ID IN ?", nextRuleSetIDs).Find(&nextDeps)
if result.Error != nil {
err = result.Error
return
}
nextRuleSetIDs = nextRuleSetIDs[:0]
for _, nextDep := range nextDeps {
for _, dep := range nextDep.DependsOn {
if seen[dep.ID] {
continue
}
if dep.ID == r.ID {
err = DependencyCyclicError{}
return
}
seen[dep.ID] = true
nextRuleSetIDs = append(nextRuleSetIDs, dep.ID)
}
}
}

return
}

//
// Rule - Analysis rule.
type Rule struct {
Model
Name string
Description string
Labels JSON `gorm:"type:json"`
RuleSetID uint `gorm:"uniqueIndex:RuleA;not null"`
RuleSet *RuleSet
FileID *uint `gorm:"uniqueIndex:RuleA" ref:"file"`
File *File
}

//
// Target - analysis rule selector.
type Target struct {
Model
UUID *string `gorm:"uniqueIndex"`
Name string `gorm:"uniqueIndex;not null"`
Description string
Choice bool
Labels JSON `gorm:"type:json"`
ImageID uint `gorm:"index" ref:"file"`
Image *File
RuleSetID *uint `gorm:"index"`
RuleSet *RuleSet
}

func (r *Target) Builtin() bool {
return r.UUID != nil
}
Loading
Loading