Skip to content

Commit bac28b7

Browse files
authored
Merge pull request #3129 from semaphoreui/sqlite
feat(be): sqlite support
2 parents fe88b52 + 5e25e89 commit bac28b7

File tree

19 files changed

+31808
-31131
lines changed

19 files changed

+31808
-31131
lines changed

.github/workflows/dev.yml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,34 @@ jobs:
225225
run: |
226226
chmod +x ./semaphore && ./semaphore migrate --config config.json
227227
228+
migrate-sqlite:
229+
runs-on: ubuntu-latest
230+
231+
needs:
232+
- build-local
233+
234+
steps:
235+
- name: Download artifacts
236+
uses: actions/download-artifact@v4
237+
with:
238+
name: semaphore
239+
240+
- name: Write config
241+
run: |
242+
cat > config.json <<EOF
243+
{
244+
"sqlite": {
245+
"host": "/tmp/db.sqlite"
246+
},
247+
"dialect": "sqlite",
248+
"email_alert": false
249+
}
250+
EOF
251+
252+
- name: Migrate database
253+
run: |
254+
chmod +x ./semaphore && ./semaphore migrate --config config.json
255+
228256
integrate-boltdb:
229257
runs-on: ubuntu-latest
230258

@@ -532,6 +560,68 @@ jobs:
532560
task dredd:hooks
533561
task dredd:test
534562
563+
integrate-sqlite:
564+
runs-on: ubuntu-latest
565+
566+
needs:
567+
- migrate-sqlite
568+
569+
steps:
570+
- name: Checkout source
571+
uses: actions/checkout@v4
572+
573+
- name: Setup golang
574+
uses: actions/setup-go@v5
575+
with:
576+
go-version: '^1.21.0'
577+
578+
- name: Setup nodejs
579+
uses: actions/setup-node@v4
580+
with:
581+
node-version: '16'
582+
cache: 'npm'
583+
cache-dependency-path: web/package-lock.json
584+
585+
- name: Install go-task
586+
run: |
587+
go install github.com/go-task/task/v3/cmd/task@latest
588+
589+
- name: Download artifacts
590+
uses: actions/download-artifact@v4
591+
with:
592+
name: semaphore
593+
594+
- name: Write config
595+
run: |
596+
cat > config.stdin <<EOF
597+
4
598+
/tmp/database.sqlite
599+
/tmp/semaphore
600+
http://localhost:3000
601+
no
602+
no
603+
no
604+
no
605+
no
606+
no
607+
$(pwd)/.dredd
608+
admin
609+
admin@localhost
610+
Developer
611+
password
612+
EOF
613+
614+
- name: Execute setup
615+
run: |
616+
chmod +x ./semaphore && ./semaphore setup - < config.stdin
617+
618+
- name: Launch dredd
619+
run: |
620+
task dredd:goodman
621+
task dredd:deps
622+
task dredd:hooks
623+
task dredd:test
624+
535625
deploy-server:
536626
runs-on: ubuntu-latest
537627
if: github.repository_owner == 'semaphoreui'

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ api/public/**/*
1313
/config.runner.key
1414
/.dredd/config.json
1515
/database.boltdb
16+
/database.sqlite
1617
/database.boltdb.lock
1718
/database_test.boltdb
1819
.DS_Store

cli/setup/setup.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ func InteractiveSetup(conf *util.ConfigType) {
115115
1 - MySQL
116116
2 - BoltDB
117117
3 - PostgreSQL
118+
4 - SQLite
118119
`
119120

120121
var db int
@@ -130,6 +131,9 @@ func InteractiveSetup(conf *util.ConfigType) {
130131
case 3:
131132
conf.Dialect = util.DbDriverPostgres
132133
scanPostgres(conf)
134+
case 4:
135+
conf.Dialect = util.DbDriverSQLite
136+
scanSQLite(conf)
133137
}
134138

135139
defaultPlaybookPath := filepath.Join(os.TempDir(), "semaphore")
@@ -183,13 +187,11 @@ func InteractiveSetup(conf *util.ConfigType) {
183187
}
184188

185189
func scanBoltDb(conf *util.ConfigType) {
186-
workingDirectory, err := os.Getwd()
187-
if err != nil {
188-
workingDirectory = os.TempDir()
189-
}
190-
defaultBoltDBPath := filepath.Join(workingDirectory, "database.boltdb")
191-
conf.BoltDb = &util.DbConfig{}
192-
askValue("db filename", defaultBoltDBPath, &conf.BoltDb.Hostname)
190+
conf.BoltDb = scanFileDB("database.boltdb")
191+
}
192+
193+
func scanSQLite(conf *util.ConfigType) {
194+
conf.SQLite = scanFileDB("database.sqlite")
193195
}
194196

195197
func scanMySQL(conf *util.ConfigType) {
@@ -214,6 +216,17 @@ func scanPostgres(conf *util.ConfigType) {
214216
}
215217
}
216218

219+
func scanFileDB(defaultDbFile string) *util.DbConfig {
220+
workingDirectory, err := os.Getwd()
221+
if err != nil {
222+
workingDirectory = os.TempDir()
223+
}
224+
defaultDBPath := filepath.Join(workingDirectory, defaultDbFile)
225+
conf := &util.DbConfig{}
226+
askValue("db Hostname", defaultDBPath, &conf.Hostname)
227+
return conf
228+
}
229+
217230
func scanErrorChecker(n int, err error) {
218231
if err != nil && err.Error() != "unexpected newline" {
219232
log.Warn("An input error occurred: " + err.Error())

db/Migration.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package db
33
import (
44
"fmt"
55
"github.com/semaphoreui/semaphore/pkg/tz"
6+
"github.com/semaphoreui/semaphore/util"
67
"slices"
78
"strconv"
89
"strings"
@@ -21,7 +22,14 @@ func (m Migration) HumanoidVersion() string {
2122
return "v" + m.Version
2223
}
2324

24-
func GetMigrations() []Migration {
25+
func GetMigrations(dialect string) []Migration {
26+
if dialect == util.DbDriverSQLite {
27+
return []Migration{
28+
{Version: "2.15.1.sqlite"},
29+
{Version: "2.16.0.sqlite"},
30+
}
31+
}
32+
2533
return []Migration{
2634
{Version: "0.0.0"},
2735
{Version: "1.0.0"},
@@ -187,7 +195,7 @@ func Rollback(d Store, targetVersion string) error {
187195

188196
didRun := false
189197

190-
migrations := GetMigrations()
198+
migrations := GetMigrations(d.GetDialect())
191199
slices.Reverse(migrations)
192200

193201
for _, version := range migrations {
@@ -220,7 +228,7 @@ func Rollback(d Store, targetVersion string) error {
220228
func Migrate(d Store, targetVersion *string) error {
221229
didRun := false
222230

223-
for _, version := range GetMigrations() {
231+
for _, version := range GetMigrations(d.GetDialect()) {
224232

225233
if targetVersion != nil && version.Compare(Migration{Version: *targetVersion}) > 0 {
226234
break

db/Store.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ type ConnectionManager interface {
194194

195195
// MigrationManager handles database migrations
196196
type MigrationManager interface {
197+
GetDialect() string
197198
// IsInitialized indicates is database already initialized, or it is empty.
198199
// The method is useful for creating required entities in database during first run.
199200
IsInitialized() (bool, error)

db/bolt/BoltDb.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ type BoltDb struct {
4444
terraformAlias publicAlias
4545
}
4646

47+
func (d *BoltDb) GetDialect() string {
48+
return util.DbDriverBolt
49+
}
50+
4751
var terraformAliasProps = db.ObjectProps{
4852
TableName: "terraform_alias",
4953
Type: reflect.TypeOf(db.TerraformInventoryAlias{}),

db/factory/store.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ func CreateStore() db.Store {
1414
}
1515
switch config.Dialect {
1616
case util.DbDriverMySQL:
17-
return &sql.SqlDb{}
17+
return sql.CreateDb(config.Dialect)
1818
case util.DbDriverBolt:
1919
return bolt.CreateBoltDB()
2020
case util.DbDriverPostgres:
21-
return &sql.SqlDb{}
21+
return sql.CreateDb(config.Dialect)
22+
case util.DbDriverSQLite:
23+
return sql.CreateDb(config.Dialect)
2224
default:
2325
panic("Unsupported database dialect: " + config.Dialect)
2426
}

db/sql/SqlDb.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ import (
1818
"github.com/semaphoreui/semaphore/pkg/task_logger"
1919
"github.com/semaphoreui/semaphore/util"
2020
log "github.com/sirupsen/logrus"
21+
_ "modernc.org/sqlite" // Import the driver
2122
)
2223

2324
type SqlDb struct {
24-
sql *gorp.DbMap
25+
sql *gorp.DbMap
26+
dialect string
2527
}
2628

2729
var initialSQL = `
@@ -35,6 +37,14 @@ create table ` + "`migrations`" + ` (
3537
//go:embed migrations/*.sql
3638
var dbAssets embed.FS
3739

40+
func CreateDb(dialect string) *SqlDb {
41+
return &SqlDb{dialect: dialect}
42+
}
43+
44+
func (d *SqlDb) GetDialect() string {
45+
return d.dialect
46+
}
47+
3848
func getQueryForParams(q squirrel.SelectBuilder, prefix string, props db.ObjectProps, params db.RetrieveQueryParams) (res squirrel.SelectBuilder, err error) {
3949
pp, err := params.Validate(props)
4050
if err != nil {
@@ -134,7 +144,7 @@ func (d *SqlDb) insert(primaryKeyColumnName string, query string, args ...any) (
134144
return 0, err
135145
}
136146
default:
137-
res, err := d.exec(query, args...)
147+
res, err := d.sql.Exec(d.PrepareQuery(query), args...)
138148
if err != nil {
139149
return 0, err
140150
}
@@ -371,10 +381,16 @@ func (d *SqlDb) Connect(_ string) {
371381
dialect = gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"}
372382
case util.DbDriverPostgres:
373383
dialect = gorp.PostgresDialect{}
384+
case util.DbDriverSQLite:
385+
dialect = gorp.SqliteDialect{}
374386
}
375387

376388
d.sql = &gorp.DbMap{Db: sqlDb, Dialect: dialect}
377389

390+
if d.GetDialect() == util.DbDriverSQLite {
391+
sqlDb.SetMaxOpenConns(1)
392+
}
393+
378394
d.sql.AddTableWithName(db.APIToken{}, "user__token").SetKeys(false, "id")
379395
d.sql.AddTableWithName(db.AccessKey{}, "access_key").SetKeys(true, "id")
380396
d.sql.AddTableWithName(db.Environment{}, "project__environment").SetKeys(true, "id")

0 commit comments

Comments
 (0)