refactor: combine migrations into one

Ayman Bagabas created

Change summary

server/backend/repo.go                                     |  82 ++--
server/db/logger.go                                        |   4 
server/db/migrate/0001_create_tables.go                    |  91 ++++-
server/db/migrate/0001_create_tables_postgres.up.sql       | 136 +++++--
server/db/migrate/0001_create_tables_sqlite.up.sql         |  55 +++
server/db/migrate/0002_create_lfs_tables.go                |  23 -
server/db/migrate/0002_create_lfs_tables_postgres.down.sql |   0 
server/db/migrate/0002_create_lfs_tables_postgres.up.sql   |  32 -
server/db/migrate/0002_create_lfs_tables_sqlite.down.sql   |   0 
server/db/migrate/0002_create_lfs_tables_sqlite.up.sql     |  32 -
server/db/migrate/0003_password_tokens.go                  |  23 -
server/db/migrate/0003_password_tokens_postgres.down.sql   |   2 
server/db/migrate/0003_password_tokens_postgres.up.sql     |  15 
server/db/migrate/0003_password_tokens_sqlite.down.sql     |   1 
server/db/migrate/0003_password_tokens_sqlite.up.sql       |  15 
server/db/migrate/0004_repo_owner.go                       |  23 -
server/db/migrate/0004_repo_owner_postgres.down.sql        |   1 
server/db/migrate/0004_repo_owner_postgres.up.sql          |  14 
server/db/migrate/0004_repo_owner_sqlite.down.sql          |   1 
server/db/migrate/0004_repo_owner_sqlite.up.sql            |  25 -
server/db/migrate/migrations.go                            |   3 
server/ssh/cmd/delete.go                                   |   6 
testscript/testdata/repo-delete.txtar                      |   3 
23 files changed, 265 insertions(+), 322 deletions(-)

Detailed changes

server/backend/repo.go 🔗

@@ -7,7 +7,6 @@ import (
 	"fmt"
 	"io/fs"
 	"os"
-	"os/exec"
 	"path"
 	"path/filepath"
 	"strconv"
@@ -105,19 +104,23 @@ func (d *Backend) ImportRepository(ctx context.Context, name string, user proto.
 		return nil, proto.ErrRepoExist
 	}
 
-	if err := os.MkdirAll(rp, fs.ModePerm); err != nil {
-		return nil, err
+	copts := git.CloneOptions{
+		Bare:   true,
+		Mirror: opts.Mirror,
+		Quiet:  true,
+		CommandOptions: git.CommandOptions{
+			Timeout: -1,
+			Context: ctx,
+			Envs: []string{
+				fmt.Sprintf(`GIT_SSH_COMMAND=ssh -o UserKnownHostsFile="%s" -o StrictHostKeyChecking=no -i "%s"`,
+					filepath.Join(d.cfg.DataPath, "ssh", "known_hosts"),
+					d.cfg.SSH.ClientKeyPath,
+				),
+			},
+		},
 	}
 
-	cmd := exec.CommandContext(ctx, "git", "clone", "--bare", "--mirror", remote, ".")
-	cmd.Env = append(cmd.Env,
-		fmt.Sprintf(`GIT_SSH_COMMAND=ssh -o UserKnownHostsFile="%s" -o StrictHostKeyChecking=no -i "%s"`,
-			filepath.Join(d.cfg.DataPath, "ssh", "known_hosts"),
-			d.cfg.SSH.ClientKeyPath,
-		),
-	)
-	cmd.Dir = rp
-	if err := cmd.Run(); err != nil {
+	if err := git.Clone(remote, rp, copts); err != nil {
 		d.logger.Error("failed to clone repository", "err", err, "mirror", opts.Mirror, "remote", remote, "path", rp)
 		// Cleanup the mess!
 		if rerr := os.RemoveAll(rp); rerr != nil {
@@ -135,7 +138,7 @@ func (d *Backend) ImportRepository(ctx context.Context, name string, user proto.
 
 	defer func() {
 		if err != nil {
-			if rerr := d.DeleteRepository(ctx, name, opts.LFS); rerr != nil {
+			if rerr := d.DeleteRepository(ctx, name); rerr != nil {
 				d.logger.Error("failed to delete repository", "err", rerr, "name", name)
 			}
 		}
@@ -187,51 +190,54 @@ func (d *Backend) ImportRepository(ctx context.Context, name string, user proto.
 // DeleteRepository deletes a repository.
 //
 // It implements backend.Backend.
-func (d *Backend) DeleteRepository(ctx context.Context, name string, deleteLFS bool) error {
+func (d *Backend) DeleteRepository(ctx context.Context, name string) error {
 	name = utils.SanitizeRepo(name)
 	repo := name + ".git"
 	rp := filepath.Join(d.reposPath(), repo)
 
-	return d.db.TransactionContext(ctx, func(tx *db.Tx) error {
+	err := d.db.TransactionContext(ctx, func(tx *db.Tx) error {
 		// Delete repo from cache
 		defer d.cache.Delete(name)
 
-		if deleteLFS {
-			repom, err := d.store.GetRepoByName(ctx, tx, name)
-			if err != nil {
-				return err
-			}
+		repom, err := d.store.GetRepoByName(ctx, tx, name)
+		if err != nil {
+			return db.WrapError(err)
+		}
 
-			repoID := strconv.FormatInt(repom.ID, 10)
-			strg := storage.NewLocalStorage(filepath.Join(d.cfg.DataPath, "lfs", repoID))
-			objs, err := d.store.GetLFSObjectsByName(ctx, tx, name)
-			if err != nil {
-				return err
-			}
+		repoID := strconv.FormatInt(repom.ID, 10)
+		strg := storage.NewLocalStorage(filepath.Join(d.cfg.DataPath, "lfs", repoID))
+		objs, err := d.store.GetLFSObjectsByName(ctx, tx, name)
+		if err != nil {
+			return db.WrapError(err)
+		}
 
-			for _, obj := range objs {
-				p := lfs.Pointer{
-					Oid:  obj.Oid,
-					Size: obj.Size,
-				}
+		for _, obj := range objs {
+			p := lfs.Pointer{
+				Oid:  obj.Oid,
+				Size: obj.Size,
+			}
 
-				d.logger.Debug("deleting lfs object", "repo", name, "oid", obj.Oid)
-				if err := strg.Delete(path.Join("objects", p.RelativePath())); err != nil {
-					d.logger.Error("failed to delete lfs object", "repo", name, "err", err, "oid", obj.Oid)
-				}
+			d.logger.Debug("deleting lfs object", "repo", name, "oid", obj.Oid)
+			if err := strg.Delete(path.Join("objects", p.RelativePath())); err != nil {
+				d.logger.Error("failed to delete lfs object", "repo", name, "err", err, "oid", obj.Oid)
 			}
 		}
 
 		if err := d.store.DeleteRepoByName(ctx, tx, name); err != nil {
-			return err
+			return db.WrapError(err)
 		}
 
 		return os.RemoveAll(rp)
 	})
+	if errors.Is(err, db.ErrRecordNotFound) {
+		return proto.ErrRepoNotFound
+	}
+
+	return err
 }
 
 // DeleteUserRepositories deletes all user repositories.
-func (d *Backend) DeleteUserRepositories(ctx context.Context, username string, deleteLFS bool) error {
+func (d *Backend) DeleteUserRepositories(ctx context.Context, username string) error {
 	return d.db.TransactionContext(ctx, func(tx *db.Tx) error {
 		user, err := d.store.FindUserByUsername(ctx, tx, username)
 		if err != nil {
@@ -244,7 +250,7 @@ func (d *Backend) DeleteUserRepositories(ctx context.Context, username string, d
 		}
 
 		for _, repo := range repos {
-			if err := d.DeleteRepository(ctx, repo.Name, deleteLFS); err != nil {
+			if err := d.DeleteRepository(ctx, repo.Name); err != nil {
 				return err
 			}
 		}

server/db/logger.go 🔗

@@ -3,6 +3,7 @@ package db
 import (
 	"context"
 	"database/sql"
+	"strings"
 
 	"github.com/charmbracelet/log"
 	"github.com/jmoiron/sqlx"
@@ -10,6 +11,9 @@ import (
 
 func trace(l *log.Logger, query string, args ...interface{}) {
 	if l != nil {
+		// Remove newlines and tabs
+		query = strings.ReplaceAll(query, "\t", "")
+		query = strings.TrimSpace(query)
 		l.Debug("trace", "query", query, "args", args)
 	}
 }

server/db/migrate/0001_create_tables.go 🔗

@@ -25,65 +25,110 @@ var createTables = Migration{
 		insert := "INSERT "
 
 		// Alter old tables (if exist)
-		// This is to support prior versions of Soft Serve
+		// This is to support prior versions of Soft Serve v0.6
 		switch tx.DriverName() {
 		case "sqlite3", "sqlite":
 			insert += "OR IGNORE "
 
 			hasUserTable := hasTable(tx, "user")
 			if hasUserTable {
-				if _, err := tx.ExecContext(ctx, "ALTER TABLE user RENAME TO users"); err != nil {
+				if _, err := tx.ExecContext(ctx, "ALTER TABLE user RENAME TO user_old"); err != nil {
 					return err
 				}
 			}
 
 			if hasTable(tx, "public_key") {
-				if _, err := tx.ExecContext(ctx, "ALTER TABLE public_key RENAME TO public_keys"); err != nil {
+				if _, err := tx.ExecContext(ctx, "ALTER TABLE public_key RENAME TO public_key_old"); err != nil {
 					return err
 				}
 			}
 
 			if hasTable(tx, "collab") {
-				if _, err := tx.ExecContext(ctx, "ALTER TABLE collab RENAME TO collabs"); err != nil {
+				if _, err := tx.ExecContext(ctx, "ALTER TABLE collab RENAME TO collab_old"); err != nil {
 					return err
 				}
 			}
 
 			if hasTable(tx, "repo") {
-				if _, err := tx.ExecContext(ctx, "ALTER TABLE repo RENAME TO repos"); err != nil {
+				if _, err := tx.ExecContext(ctx, "ALTER TABLE repo RENAME TO repo_old"); err != nil {
 					return err
 				}
 			}
+		}
 
-			// Fix username being nullable
-			if hasUserTable {
+		if err := migrateUp(ctx, tx, createTablesVersion, createTablesName); err != nil {
+			return err
+		}
+
+		switch tx.DriverName() {
+		case "sqlite3", "sqlite":
+
+			if _, err := tx.ExecContext(ctx, "PRAGMA foreign_keys = OFF"); err != nil {
+				return err
+			}
+
+			if hasTable(tx, "user_old") {
 				sqlm := `
-				PRAGMA foreign_keys = OFF;
+				INSERT INTO users (id, username, admin, updated_at)
+					SELECT id, username, admin, updated_at FROM user_old;
+				`
+				if _, err := tx.ExecContext(ctx, sqlm); err != nil {
+					return err
+				}
+			}
 
-				CREATE TABLE users_new (
-					id INTEGER PRIMARY KEY AUTOINCREMENT,
-					username TEXT NOT NULL UNIQUE,
-					admin BOOLEAN NOT NULL,
-					created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-					updated_at DATETIME NOT NULL
-				);
+			if hasTable(tx, "public_key_old") {
+				// Check duplicate keys
+				pks := []struct {
+					ID        string `db:"id"`
+					PublicKey string `db:"public_key"`
+				}{}
+				if err := tx.SelectContext(ctx, &pks, "SELECT id, public_key FROM public_key_old"); err != nil {
+					return err
+				}
 
-				INSERT INTO users_new (username, admin, updated_at)
-					SELECT username, admin, updated_at FROM users;
+				pkss := map[string]struct{}{}
+				for _, pk := range pks {
+					if _, ok := pkss[pk.PublicKey]; ok {
+						return fmt.Errorf("duplicate public key: %q, please remove the duplicate key and try again", pk.PublicKey)
+					}
+					pkss[pk.PublicKey] = struct{}{}
+				}
 
-				DROP TABLE users;
-				ALTER TABLE users_new RENAME TO users;
+				sqlm := `
+				INSERT INTO public_keys (id, user_id, public_key, created_at, updated_at)
+					SELECT id, user_id, public_key, created_at, updated_at FROM public_key_old;
+				`
+				if _, err := tx.ExecContext(ctx, sqlm); err != nil {
+					return err
+				}
+			}
 
-				PRAGMA foreign_keys = ON;
+			if hasTable(tx, "repo_old") {
+				sqlm := `
+				INSERT INTO repos (id, name, project_name, description, private,mirror, hidden, created_at, updated_at, user_id)
+					SELECT id, name, project_name, description, private, mirror, hidden, created_at, updated_at, (
+						SELECT id FROM users WHERE admin = true ORDER BY id LIMIT 1
+				) FROM repo_old;
 				`
 				if _, err := tx.ExecContext(ctx, sqlm); err != nil {
 					return err
 				}
 			}
-		}
 
-		if err := migrateUp(ctx, tx, createTablesVersion, createTablesName); err != nil {
-			return err
+			if hasTable(tx, "collab_old") {
+				sqlm := `
+				INSERT INTO collabs (id, user_id, repo_id, created_at, updated_at)
+					SELECT id, user_id, repo_id, created_at, updated_at FROM collab_old;
+				`
+				if _, err := tx.ExecContext(ctx, sqlm); err != nil {
+					return err
+				}
+			}
+
+			if _, err := tx.ExecContext(ctx, "PRAGMA foreign_keys = ON"); err != nil {
+				return err
+			}
 		}
 
 		// Insert default user

server/db/migrate/0001_create_tables_postgres.up.sql 🔗

@@ -1,59 +1,109 @@
 CREATE TABLE IF NOT EXISTS settings (
-    id SERIAL PRIMARY KEY,
-    key TEXT NOT NULL UNIQUE,
-    value TEXT NOT NULL,
-    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at TIMESTAMP NOT NULL
+  id SERIAL PRIMARY KEY,
+  key TEXT NOT NULL UNIQUE,
+  value TEXT NOT NULL,
+  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at TIMESTAMP NOT NULL
 );
 
 CREATE TABLE IF NOT EXISTS users (
-    id SERIAL PRIMARY KEY,
-    username TEXT NOT NULL UNIQUE,
-    admin BOOLEAN NOT NULL,
-    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at TIMESTAMP NOT NULL
+  id SERIAL PRIMARY KEY,
+  username TEXT NOT NULL UNIQUE,
+  admin BOOLEAN NOT NULL,
+  password TEXT,
+  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at TIMESTAMP NOT NULL
 );
 
 CREATE TABLE IF NOT EXISTS public_keys (
-    id SERIAL PRIMARY KEY,
-    user_id INTEGER NOT NULL,
-    public_key TEXT NOT NULL UNIQUE,
-    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at TIMESTAMP NOT NULL,
-    UNIQUE (user_id, public_key),
-    CONSTRAINT user_id_fk
-    FOREIGN KEY(user_id) REFERENCES users(id)
-    ON DELETE CASCADE
-    ON UPDATE CASCADE
+  id SERIAL PRIMARY KEY,
+  user_id INTEGER NOT NULL,
+  public_key TEXT NOT NULL UNIQUE,
+  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at TIMESTAMP NOT NULL,
+  CONSTRAINT user_id_fk
+  FOREIGN KEY(user_id) REFERENCES users(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
 );
 
 CREATE TABLE IF NOT EXISTS repos (
-    id SERIAL PRIMARY KEY,
-    name TEXT NOT NULL UNIQUE,
-    project_name TEXT NOT NULL,
-    description TEXT NOT NULL,
-    private BOOLEAN NOT NULL,
-    mirror BOOLEAN NOT NULL,
-    hidden BOOLEAN NOT NULL,
-    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at TIMESTAMP NOT NULL
+  id SERIAL PRIMARY KEY,
+  name TEXT NOT NULL UNIQUE,
+  project_name TEXT NOT NULL,
+  description TEXT NOT NULL,
+  private BOOLEAN NOT NULL,
+  mirror BOOLEAN NOT NULL,
+  hidden BOOLEAN NOT NULL,
+  user_id INTEGER NOT NULL,
+  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at TIMESTAMP NOT NULL,
+  CONSTRAINT user_id_fk
+  FOREIGN KEY(user_id) REFERENCES users(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
 );
 
 CREATE TABLE IF NOT EXISTS collabs (
-    id SERIAL PRIMARY KEY,
-    user_id INTEGER NOT NULL,
-    repo_id INTEGER NOT NULL,
-    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at TIMESTAMP NOT NULL,
-    UNIQUE (user_id, repo_id),
-    CONSTRAINT user_id_fk
-    FOREIGN KEY(user_id) REFERENCES users(id)
-    ON DELETE CASCADE
-    ON UPDATE CASCADE,
-    CONSTRAINT repo_id_fk
-    FOREIGN KEY(repo_id) REFERENCES repos(id)
-    ON DELETE CASCADE
-    ON UPDATE CASCADE
+  id SERIAL PRIMARY KEY,
+  user_id INTEGER NOT NULL,
+  repo_id INTEGER NOT NULL,
+  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at TIMESTAMP NOT NULL,
+  UNIQUE (user_id, repo_id),
+  CONSTRAINT user_id_fk
+  FOREIGN KEY(user_id) REFERENCES users(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE,
+  CONSTRAINT repo_id_fk
+  FOREIGN KEY(repo_id) REFERENCES repos(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
 );
 
+CREATE TABLE IF NOT EXISTS lfs_objects (
+  id SERIAL PRIMARY KEY,
+  oid TEXT NOT NULL,
+  size INTEGER NOT NULL,
+  repo_id INTEGER NOT NULL,
+  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at TIMESTAMP NOT NULL,
+  UNIQUE (oid, repo_id),
+  CONSTRAINT repo_id_fk
+  FOREIGN KEY(repo_id) REFERENCES repos(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS lfs_locks (
+  id SERIAL PRIMARY KEY,
+  repo_id INTEGER NOT NULL,
+  user_id INTEGER NOT NULL,
+  path TEXT NOT NULL,
+  refname TEXT,
+  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at TIMESTAMP NOT NULL,
+  UNIQUE (repo_id, path),
+  CONSTRAINT repo_id_fk
+  FOREIGN KEY(repo_id) REFERENCES repos(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE,
+  CONSTRAINT user_id_fk
+  FOREIGN KEY(user_id) REFERENCES users(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
+);
 
+CREATE TABLE IF NOT EXISTS access_tokens (
+  id SERIAL PRIMARY KEY,
+  name text NOT NULL,
+  token TEXT NOT NULL UNIQUE,
+  user_id INTEGER NOT NULL,
+  expires_at TIMESTAMP,
+  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at TIMESTAMP NOT NULL,
+  CONSTRAINT user_id_fk
+  FOREIGN KEY (user_id) REFERENCES users(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
+);

server/db/migrate/0001_create_tables_sqlite.up.sql 🔗

@@ -10,6 +10,7 @@ CREATE TABLE IF NOT EXISTS users (
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   username TEXT NOT NULL UNIQUE,
   admin BOOLEAN NOT NULL,
+  password TEXT,
   created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
   updated_at DATETIME NOT NULL
 );
@@ -20,7 +21,6 @@ CREATE TABLE IF NOT EXISTS public_keys (
   public_key TEXT NOT NULL UNIQUE,
   created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
   updated_at DATETIME NOT NULL,
-  UNIQUE (user_id, public_key),
   CONSTRAINT user_id_fk
   FOREIGN KEY(user_id) REFERENCES users(id)
   ON DELETE CASCADE
@@ -35,8 +35,13 @@ CREATE TABLE IF NOT EXISTS repos (
   private BOOLEAN NOT NULL,
   mirror BOOLEAN NOT NULL,
   hidden BOOLEAN NOT NULL,
+  user_id INTEGER NOT NULL,
   created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME NOT NULL
+  updated_at DATETIME NOT NULL,
+  CONSTRAINT user_id_fk
+  FOREIGN KEY(user_id) REFERENCES users(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
 );
 
 CREATE TABLE IF NOT EXISTS collabs (
@@ -56,3 +61,49 @@ CREATE TABLE IF NOT EXISTS collabs (
   ON UPDATE CASCADE
 );
 
+CREATE TABLE IF NOT EXISTS lfs_objects (
+  id INTEGER PRIMARY KEY AUTOINCREMENT,
+  oid TEXT NOT NULL,
+  size INTEGER NOT NULL,
+  repo_id INTEGER NOT NULL,
+  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at DATETIME NOT NULL,
+  UNIQUE (oid, repo_id),
+  CONSTRAINT repo_id_fk
+  FOREIGN KEY(repo_id) REFERENCES repos(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS lfs_locks (
+  id INTEGER PRIMARY KEY AUTOINCREMENT,
+  repo_id INTEGER NOT NULL,
+  user_id INTEGER NOT NULL,
+  path TEXT NOT NULL,
+  refname TEXT,
+  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at DATETIME NOT NULL,
+  UNIQUE (repo_id, path),
+  CONSTRAINT repo_id_fk
+  FOREIGN KEY(repo_id) REFERENCES repos(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE,
+  CONSTRAINT user_id_fk
+  FOREIGN KEY(user_id) REFERENCES users(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS access_tokens (
+  id INTEGER primary key autoincrement,
+  token text NOT NULL UNIQUE,
+  name text NOT NULL,
+  user_id INTEGER NOT NULL,
+  expires_at DATETIME,
+  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  updated_at DATETIME NOT NULL,
+  CONSTRAINT user_id_fk
+  FOREIGN KEY (user_id) REFERENCES users(id)
+  ON DELETE CASCADE
+  ON UPDATE CASCADE
+);

server/db/migrate/0002_create_lfs_tables.go 🔗

@@ -1,23 +0,0 @@
-package migrate
-
-import (
-	"context"
-
-	"github.com/charmbracelet/soft-serve/server/db"
-)
-
-const (
-	createLFSTablesName    = "create lfs tables"
-	createLFSTablesVersion = 2
-)
-
-var createLFSTables = Migration{
-	Version: createLFSTablesVersion,
-	Name:    createLFSTablesName,
-	Migrate: func(ctx context.Context, tx *db.Tx) error {
-		return migrateUp(ctx, tx, createLFSTablesVersion, createLFSTablesName)
-	},
-	Rollback: func(ctx context.Context, tx *db.Tx) error {
-		return migrateDown(ctx, tx, createLFSTablesVersion, createLFSTablesName)
-	},
-}

server/db/migrate/0002_create_lfs_tables_postgres.up.sql 🔗

@@ -1,32 +0,0 @@
-CREATE TABLE IF NOT EXISTS lfs_objects (
-  id SERIAL PRIMARY KEY,
-  oid TEXT NOT NULL,
-  size INTEGER NOT NULL,
-  repo_id INTEGER NOT NULL,
-  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  updated_at TIMESTAMP NOT NULL,
-  UNIQUE (oid, repo_id),
-  CONSTRAINT repo_id_fk
-  FOREIGN KEY(repo_id) REFERENCES repos(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE
-);
-
-CREATE TABLE IF NOT EXISTS lfs_locks (
-  id SERIAL PRIMARY KEY,
-  repo_id INTEGER NOT NULL,
-  user_id INTEGER NOT NULL,
-  path TEXT NOT NULL,
-  refname TEXT,
-  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  updated_at TIMESTAMP NOT NULL,
-  UNIQUE (repo_id, path),
-  CONSTRAINT repo_id_fk
-  FOREIGN KEY(repo_id) REFERENCES repos(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE,
-  CONSTRAINT user_id_fk
-  FOREIGN KEY(user_id) REFERENCES users(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE
-);

server/db/migrate/0002_create_lfs_tables_sqlite.up.sql 🔗

@@ -1,32 +0,0 @@
-CREATE TABLE IF NOT EXISTS lfs_objects (
-  id INTEGER PRIMARY KEY AUTOINCREMENT,
-  oid TEXT NOT NULL,
-  size INTEGER NOT NULL,
-  repo_id INTEGER NOT NULL,
-  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME NOT NULL,
-  UNIQUE (oid, repo_id),
-  CONSTRAINT repo_id_fk
-  FOREIGN KEY(repo_id) REFERENCES repos(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE
-);
-
-CREATE TABLE IF NOT EXISTS lfs_locks (
-  id INTEGER PRIMARY KEY AUTOINCREMENT,
-  repo_id INTEGER NOT NULL,
-  user_id INTEGER NOT NULL,
-  path TEXT NOT NULL,
-  refname TEXT,
-  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME NOT NULL,
-  UNIQUE (repo_id, path),
-  CONSTRAINT repo_id_fk
-  FOREIGN KEY(repo_id) REFERENCES repos(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE,
-  CONSTRAINT user_id_fk
-  FOREIGN KEY(user_id) REFERENCES users(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE
-);

server/db/migrate/0003_password_tokens.go 🔗

@@ -1,23 +0,0 @@
-package migrate
-
-import (
-	"context"
-
-	"github.com/charmbracelet/soft-serve/server/db"
-)
-
-const (
-	passwordTokensName    = "password tokens"
-	passwordTokensVersion = 3
-)
-
-var passwordTokens = Migration{
-	Version: passwordTokensVersion,
-	Name:    passwordTokensName,
-	Migrate: func(ctx context.Context, tx *db.Tx) error {
-		return migrateUp(ctx, tx, passwordTokensVersion, passwordTokensName)
-	},
-	Rollback: func(ctx context.Context, tx *db.Tx) error {
-		return migrateDown(ctx, tx, passwordTokensVersion, passwordTokensName)
-	},
-}

server/db/migrate/0003_password_tokens_postgres.up.sql 🔗

@@ -1,15 +0,0 @@
-ALTER TABLE users ADD COLUMN password TEXT;
-
-CREATE TABLE IF NOT EXISTS access_tokens (
-  id SERIAL PRIMARY KEY,
-  name text NOT NULL,
-  token TEXT NOT NULL UNIQUE,
-  user_id INTEGER NOT NULL,
-  expires_at TIMESTAMP,
-  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  updated_at TIMESTAMP NOT NULL,
-  CONSTRAINT user_id_fk
-  FOREIGN KEY (user_id) REFERENCES users(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE
-);

server/db/migrate/0003_password_tokens_sqlite.up.sql 🔗

@@ -1,15 +0,0 @@
-ALTER TABLE users ADD COLUMN password TEXT;
-
-CREATE TABLE IF NOT EXISTS access_tokens (
-  id INTEGER primary key autoincrement,
-  token text NOT NULL UNIQUE,
-  name text NOT NULL,
-  user_id INTEGER NOT NULL,
-  expires_at DATETIME,
-  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME NOT NULL,
-  CONSTRAINT user_id_fk
-  FOREIGN KEY (user_id) REFERENCES users(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE
-);

server/db/migrate/0004_repo_owner.go 🔗

@@ -1,23 +0,0 @@
-package migrate
-
-import (
-	"context"
-
-	"github.com/charmbracelet/soft-serve/server/db"
-)
-
-const (
-	repoOwnerName    = "repo owner"
-	repoOwnerVersion = 4
-)
-
-var repoOwner = Migration{
-	Version: repoOwnerVersion,
-	Name:    repoOwnerName,
-	Migrate: func(ctx context.Context, tx *db.Tx) error {
-		return migrateUp(ctx, tx, repoOwnerVersion, repoOwnerName)
-	},
-	Rollback: func(ctx context.Context, tx *db.Tx) error {
-		return migrateDown(ctx, tx, repoOwnerVersion, repoOwnerName)
-	},
-}

server/db/migrate/0004_repo_owner_postgres.up.sql 🔗

@@ -1,14 +0,0 @@
-ALTER TABLE repos ADD COLUMN user_id INTEGER;
-
-UPDATE repos SET user_id = (
-  SELECT id FROM users WHERE admin = true ORDER BY id LIMIT 1
-);
-
-ALTER TABLE repos
-ALTER COLUMN user_id SET NOT NULL;
-
-ALTER TABLE repos
-ADD CONSTRAINT user_id_fk
-FOREIGN KEY(user_id) REFERENCES users(id)
-ON DELETE CASCADE
-ON UPDATE CASCADE;

server/db/migrate/0004_repo_owner_sqlite.up.sql 🔗

@@ -1,25 +0,0 @@
-ALTER TABLE repos RENAME TO repos_old;
-
-CREATE TABLE repos (
-  id INTEGER PRIMARY KEY AUTOINCREMENT,
-  name TEXT NOT NULL UNIQUE,
-  project_name TEXT NOT NULL,
-  description TEXT NOT NULL,
-  private BOOLEAN NOT NULL,
-  mirror BOOLEAN NOT NULL,
-  hidden BOOLEAN NOT NULL,
-  user_id INTEGER NOT NULL,
-  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME NOT NULL,
-  CONSTRAINT user_id_fk
-  FOREIGN KEY(user_id) REFERENCES users(id)
-  ON DELETE CASCADE
-  ON UPDATE CASCADE
-);
-
-INSERT INTO repos (id, name, project_name, description, private, mirror, hidden, user_id, created_at, updated_at)
-SELECT id, name, project_name, description, private, mirror, hidden, (
-  SELECT id FROM users WHERE admin = true ORDER BY id LIMIT 1
-), created_at, updated_at
-FROM repos_old;
-

server/db/migrate/migrations.go 🔗

@@ -16,9 +16,6 @@ var sqls embed.FS
 // Keep this in order of execution, oldest to newest.
 var migrations = []Migration{
 	createTables,
-	createLFSTables,
-	passwordTokens,
-	repoOwner,
 }
 
 func execMigration(ctx context.Context, tx *db.Tx, version int, name string, down bool) error {

server/ssh/cmd/delete.go 🔗

@@ -6,8 +6,6 @@ import (
 )
 
 func deleteCommand() *cobra.Command {
-	var lfs bool
-
 	cmd := &cobra.Command{
 		Use:               "delete REPOSITORY",
 		Aliases:           []string{"del", "remove", "rm"},
@@ -19,11 +17,9 @@ func deleteCommand() *cobra.Command {
 			be := backend.FromContext(ctx)
 			name := args[0]
 
-			return be.DeleteRepository(ctx, name, lfs)
+			return be.DeleteRepository(ctx, name)
 		},
 	}
 
-	cmd.Flags().BoolVarP(&lfs, "lfs", "", false, "Delete LFS objects")
-
 	return cmd
 }

testscript/testdata/repo-delete.txtar 🔗

@@ -3,6 +3,7 @@
 soft repo create repo1
 soft repo create repo-to-delete
 soft repo delete repo-to-delete
-soft repo delete nope # repo delete never fails
+! soft repo delete nope
+stderr '.*not found.*'
 soft repo list
 stdout 'repo1'