GameOver1337 / GitClone Public
К репозиторию
3.2 KB
internal/db/db.go
3.2 KB
1package db
2
3import (
4 "database/sql"
5 "fmt"
6
7 _ "modernc.org/sqlite"
8)
9
10var DB *sql.DB
11
12func Init(dbPath string) error {
13 var err error
14 DB, err = sql.Open("sqlite", dbPath)
15 if err != nil {
16 return fmt.Errorf("open db: %w", err)
17 }
18
19 DB.SetMaxOpenConns(1)
20 DB.SetMaxIdleConns(1)
21
22 if err := DB.Ping(); err != nil {
23 return fmt.Errorf("ping db: %w", err)
24 }
25
26 for _, pragma := range []string{
27 `PRAGMA busy_timeout = 5000`,
28 `PRAGMA journal_mode = WAL`,
29 `PRAGMA foreign_keys = ON`,
30 } {
31 if _, err := DB.Exec(pragma); err != nil {
32 return fmt.Errorf("%s: %w", pragma, err)
33 }
34 }
35
36 if err := createTables(); err != nil {
37 return fmt.Errorf("create tables: %w", err)
38 }
39
40 if err := migrateCloneURLs(); err != nil {
41 return fmt.Errorf("migrate clone urls: %w", err)
42 }
43
44 // После перезапуска зависшие сборки некому завершить — помечаем их failed.
45 if _, err := DB.Exec(
46 `UPDATE builds SET status = 'failed', finished_at = CURRENT_TIMESTAMP WHERE status = 'running'`,
47 ); err != nil {
48 return fmt.Errorf("reset running builds: %w", err)
49 }
50
51 return nil
52}
53
54func createTables() error {
55 schema := `
56 CREATE TABLE IF NOT EXISTS users (
57 id INTEGER PRIMARY KEY AUTOINCREMENT,
58 username TEXT UNIQUE NOT NULL,
59 email TEXT UNIQUE NOT NULL,
60 password_hash TEXT NOT NULL,
61 avatar_url TEXT DEFAULT '',
62 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
63 );
64
65 CREATE TABLE IF NOT EXISTS repositories (
66 id INTEGER PRIMARY KEY AUTOINCREMENT,
67 name TEXT NOT NULL,
68 owner_id INTEGER NOT NULL REFERENCES users(id),
69 description TEXT DEFAULT '',
70 is_private BOOLEAN DEFAULT 0,
71 is_archived BOOLEAN DEFAULT 0,
72 clone_url TEXT NOT NULL,
73 created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
74 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
75 UNIQUE(name, owner_id)
76 );
77
78 CREATE TABLE IF NOT EXISTS builds (
79 id INTEGER PRIMARY KEY AUTOINCREMENT,
80 repo_id INTEGER NOT NULL REFERENCES repositories(id),
81 branch TEXT DEFAULT 'main',
82 build_type TEXT NOT NULL,
83 status TEXT NOT NULL DEFAULT 'pending',
84 log_file TEXT DEFAULT '',
85 started_at DATETIME DEFAULT CURRENT_TIMESTAMP,
86 finished_at DATETIME,
87 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
88 );
89
90 CREATE TABLE IF NOT EXISTS releases (
91 id INTEGER PRIMARY KEY AUTOINCREMENT,
92 repo_id INTEGER NOT NULL REFERENCES repositories(id),
93 tag TEXT NOT NULL,
94 title TEXT NOT NULL,
95 body TEXT DEFAULT '',
96 is_prerelease BOOLEAN DEFAULT 0,
97 created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
98 UNIQUE(repo_id, tag)
99 );
100
101 CREATE INDEX IF NOT EXISTS idx_repos_owner ON repositories(owner_id);
102 CREATE INDEX IF NOT EXISTS idx_builds_repo ON builds(repo_id);
103 CREATE INDEX IF NOT EXISTS idx_builds_status ON builds(status);
104 CREATE INDEX IF NOT EXISTS idx_releases_repo ON releases(repo_id);
105 `
106
107 _, err := DB.Exec(schema)
108 return err
109}
110
111// migrateCloneURLs переводит старые имена вида "owner--repo" в "owner/repo"
112// (git-URL теперь /owner/repo.git вместо owner--repo.git).
113func migrateCloneURLs() error {
114 _, err := DB.Exec(
115 `UPDATE repositories
116 SET clone_url = substr(clone_url, 1, instr(clone_url, '--') - 1)
117 || '/' || substr(clone_url, instr(clone_url, '--') + 2)
118 WHERE instr(clone_url, '--') > 0 AND instr(clone_url, '/') = 0`,
119 )
120 return err
121}