Skip to content

Commit

Permalink
refactor: implement database module and abstract backend (#337)
Browse files Browse the repository at this point in the history
* refactor(server): abstract database from backend

Prepare for multi database driver support

* feat(server): add db models

* feat(db): add database migrations

* feat(db): add support to postgres

* feat: implement database store logic

* refactor: use db module and abstract backend logic

* fix(db): postgres migrate sql

* feat(db): add database query tracing

* refactor: move internal packages to server

* fix(config): normalize sqlite database path

* fix,feat: support custom log path and fix logging leak in hooks

* fix(test): race condition

* refactor: tidy up files and use middlewares

* chore: add test for repo commit command

Reference: #331

* fix: lint errors

* fix: use utc time and fix git packp error format

* fix: lint errors

* fix: testscript on windows

* chore: format sql files

* fix: lint issues

re-enable revive linter

* refactor: clean up server/config

* feat: add admin command to manage server

* fix(db): use migration versions

* chore: add deprecation warning.

* refactor: move shared interfaces and errors to proto

* fix: increase golangci lint timeout

* feat: add move tests
  • Loading branch information
aymanbagabas authored Jul 17, 2023
1 parent 7cd0583 commit e398b4d
Show file tree
Hide file tree
Showing 133 changed files with 4,558 additions and 3,257 deletions.
1 change: 1 addition & 0 deletions .golangci-soft.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
run:
tests: false
timeout: 5m

issues:
include:
Expand Down
8 changes: 8 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
run:
tests: false
timeout: 5m

issues:
include:
Expand Down Expand Up @@ -27,3 +28,10 @@ linters:
- unconvert
- unparam
- whitespace

severity:
default-severity: error
rules:
- linters:
- revive
severity: info
75 changes: 75 additions & 0 deletions cmd/soft/admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"fmt"

"github.com/charmbracelet/soft-serve/server/backend"
"github.com/charmbracelet/soft-serve/server/config"
"github.com/charmbracelet/soft-serve/server/db"
"github.com/charmbracelet/soft-serve/server/db/migrate"
"github.com/spf13/cobra"
)

var (
adminCmd = &cobra.Command{
Use: "admin",
Short: "Administrate the server",
}

migrateCmd = &cobra.Command{
Use: "migrate",
Short: "Migrate the database to the latest version",
PersistentPreRunE: initBackendContext,
PersistentPostRunE: closeDBContext,
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
db := db.FromContext(ctx)
if err := migrate.Migrate(ctx, db); err != nil {
return fmt.Errorf("migration: %w", err)
}

return nil
},
}

rollbackCmd = &cobra.Command{
Use: "rollback",
Short: "Rollback the database to the previous version",
PersistentPreRunE: initBackendContext,
PersistentPostRunE: closeDBContext,
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
db := db.FromContext(ctx)
if err := migrate.Rollback(ctx, db); err != nil {
return fmt.Errorf("rollback: %w", err)
}

return nil
},
}

syncHooksCmd = &cobra.Command{
Use: "sync-hooks",
Short: "Update repository hooks",
PersistentPreRunE: initBackendContext,
PersistentPostRunE: closeDBContext,
RunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
cfg := config.FromContext(ctx)
be := backend.FromContext(ctx)
if err := initializeHooks(ctx, cfg, be); err != nil {
return fmt.Errorf("initialize hooks: %w", err)
}

return nil
},
}
)

func init() {
adminCmd.AddCommand(
syncHooksCmd,
migrateCmd,
rollbackCmd,
)
}
74 changes: 21 additions & 53 deletions cmd/soft/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,66 +11,33 @@ import (
"path/filepath"
"strings"

"github.com/charmbracelet/log"
"github.com/charmbracelet/soft-serve/server/backend"
"github.com/charmbracelet/soft-serve/server/backend/sqlite"
"github.com/charmbracelet/soft-serve/server/config"
"github.com/charmbracelet/soft-serve/server/hooks"
"github.com/spf13/cobra"
)

var (
// Deprecated: this flag is ignored.
configPath string

logFileCtxKey = struct{}{}

hookCmd = &cobra.Command{
Use: "hook",
Short: "Run git server hooks",
Long: "Handles Soft Serve git server hooks.",
Hidden: true,
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
cfg, err := config.ParseConfig(configPath)
if err != nil {
return fmt.Errorf("could not parse config: %w", err)
}

ctx = config.WithContext(ctx, cfg)

logPath := filepath.Join(cfg.DataPath, "log", "hooks.log")
f, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("opening file: %w", err)
}

ctx = context.WithValue(ctx, logFileCtxKey, f)
logger := log.FromContext(ctx)
logger.SetOutput(f)
ctx = log.WithContext(ctx, logger)
cmd.SetContext(ctx)

// Set up the backend
// TODO: support other backends
sb, err := sqlite.NewSqliteBackend(ctx)
if err != nil {
return fmt.Errorf("failed to create sqlite backend: %w", err)
}

cfg = cfg.WithBackend(sb)

return nil
},
PersistentPostRunE: func(cmd *cobra.Command, _ []string) error {
f := cmd.Context().Value(logFileCtxKey).(*os.File)
return f.Close()
},
Use: "hook",
Short: "Run git server hooks",
Long: "Handles Soft Serve git server hooks.",
Hidden: true,
PersistentPreRunE: initBackendContext,
PersistentPostRunE: closeDBContext,
}

// Git hooks read the config from the environment, based on
// $SOFT_SERVE_DATA_PATH. We already parse the config when the binary
// starts, so we don't need to do it again.
// The --config flag is now deprecated.
hooksRunE = func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
hks := backend.FromContext(ctx)
cfg := config.FromContext(ctx)
hks := cfg.Backend.(backend.Hooks)

// This is set in the server before invoking git-receive-pack/git-upload-pack
repoName := os.Getenv("SOFT_SERVE_REPO_NAME")
Expand All @@ -80,10 +47,10 @@ var (
stderr := cmd.ErrOrStderr()

cmdName := cmd.Name()
customHookPath := filepath.Join(filepath.Dir(configPath), "hooks", cmdName)
customHookPath := filepath.Join(cfg.DataPath, "hooks", cmdName)

var buf bytes.Buffer
opts := make([]backend.HookArg, 0)
opts := make([]hooks.HookArg, 0)

switch cmdName {
case hooks.PreReceiveHook, hooks.PostReceiveHook:
Expand All @@ -94,7 +61,7 @@ var (
if len(fields) != 3 {
return fmt.Errorf("invalid hook input: %s", scanner.Text())
}
opts = append(opts, backend.HookArg{
opts = append(opts, hooks.HookArg{
OldSha: fields[0],
NewSha: fields[1],
RefName: fields[2],
Expand All @@ -103,22 +70,22 @@ var (

switch cmdName {
case hooks.PreReceiveHook:
hks.PreReceive(stdout, stderr, repoName, opts)
hks.PreReceive(ctx, stdout, stderr, repoName, opts)
case hooks.PostReceiveHook:
hks.PostReceive(stdout, stderr, repoName, opts)
hks.PostReceive(ctx, stdout, stderr, repoName, opts)
}
case hooks.UpdateHook:
if len(args) != 3 {
return fmt.Errorf("invalid update hook input: %s", args)
}

hks.Update(stdout, stderr, repoName, backend.HookArg{
hks.Update(ctx, stdout, stderr, repoName, hooks.HookArg{
OldSha: args[0],
NewSha: args[1],
RefName: args[2],
})
case hooks.PostUpdateHook:
hks.PostUpdate(stdout, stderr, repoName, args...)
hks.PostUpdate(ctx, stdout, stderr, repoName, args...)
}

// Custom hooks
Expand Down Expand Up @@ -159,7 +126,7 @@ var (
)

func init() {
hookCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "path to config file")
hookCmd.PersistentFlags().StringVar(&configPath, "config", "", "path to config file (deprecated)")
hookCmd.AddCommand(
preReceiveCmd,
updateCmd,
Expand Down Expand Up @@ -211,6 +178,7 @@ fi
echo "Hi from Soft Serve update hook!"
echo
echo "Repository: $SOFT_SERVE_REPO_NAME"
echo "RefName: $refname"
echo "Change Type: $newrev_type"
echo "Old SHA1: $oldrev"
Expand Down
34 changes: 16 additions & 18 deletions cmd/soft/man.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,20 @@ import (
"github.com/spf13/cobra"
)

var (
manCmd = &cobra.Command{
Use: "man",
Short: "Generate man pages",
Args: cobra.NoArgs,
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
manPage, err := mcobra.NewManPage(1, rootCmd) //.
if err != nil {
return err
}
var manCmd = &cobra.Command{
Use: "man",
Short: "Generate man pages",
Args: cobra.NoArgs,
Hidden: true,
RunE: func(_ *cobra.Command, _ []string) error {
manPage, err := mcobra.NewManPage(1, rootCmd) //.
if err != nil {
return err
}

manPage = manPage.WithSection("Copyright", "(C) 2021-2023 Charmbracelet, Inc.\n"+
"Released under MIT license.")
fmt.Println(manPage.Build(roff.NewDocument()))
return nil
},
}
)
manPage = manPage.WithSection("Copyright", "(C) 2021-2023 Charmbracelet, Inc.\n"+
"Released under MIT license.")
fmt.Println(manPage.Build(roff.NewDocument()))
return nil
},
}
Loading

0 comments on commit e398b4d

Please sign in to comment.