(Feat): Initial Commit
This commit is contained in:
76
internal/util/command/command.go
Normal file
76
internal/util/command/command.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"allaboutapps.dev/aw/go-starter/internal/api"
|
||||
"allaboutapps.dev/aw/go-starter/internal/config"
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
LogKeyCmdExecutionID = "cmdExecutionId"
|
||||
shutdownTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
func WithServer(ctx context.Context, config config.Server, handler func(ctx context.Context, s *api.Server) error) error {
|
||||
ctx = log.With().Str(LogKeyCmdExecutionID, uuid.New().String()).Logger().WithContext(ctx)
|
||||
|
||||
zerolog.TimeFieldFormat = time.RFC3339Nano
|
||||
zerolog.SetGlobalLevel(config.Logger.Level)
|
||||
if config.Logger.PrettyPrintConsole {
|
||||
log.Logger = log.Output(zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) {
|
||||
w.TimeFormat = "15:04:05"
|
||||
}))
|
||||
}
|
||||
|
||||
s, err := api.InitNewServer(config)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to initialize server")
|
||||
}
|
||||
|
||||
start := s.Clock.Now()
|
||||
|
||||
err = handler(ctx, s)
|
||||
|
||||
elapsed := time.Since(start)
|
||||
log.Info().Dur("duration", elapsed).Msg("Command execution finished")
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Command failed")
|
||||
return err
|
||||
}
|
||||
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||
defer cancel()
|
||||
if errs := s.Shutdown(shutdownCtx); len(errs) > 0 {
|
||||
log.Error().Errs("shutdownErrors", errs).Msg("Failed to gracefully shut down server")
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewSubcommandGroup(subcommand string, subcommands ...*cobra.Command) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: fmt.Sprintf("%s <subcommand>", subcommand),
|
||||
Short: fmt.Sprintf("%s related subcommands", subcommand),
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
if err := cmd.Help(); err != nil {
|
||||
return fmt.Errorf("failed to print help: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.AddCommand(subcommands...)
|
||||
|
||||
return cmd
|
||||
}
|
||||
34
internal/util/command/command_test.go
Normal file
34
internal/util/command/command_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package command_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"allaboutapps.dev/aw/go-starter/internal/api"
|
||||
"allaboutapps.dev/aw/go-starter/internal/test"
|
||||
"allaboutapps.dev/aw/go-starter/internal/util/command"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWithServer(t *testing.T) {
|
||||
test.WithTestServer(t, func(s *api.Server) {
|
||||
ctx := t.Context()
|
||||
|
||||
var testError = errors.New("test error")
|
||||
|
||||
s.Config.Logger.PrettyPrintConsole = false
|
||||
resultErr := command.WithServer(ctx, s.Config, func(ctx context.Context, s *api.Server) error {
|
||||
var database string
|
||||
err := s.DB.QueryRowContext(ctx, "SELECT current_database();").Scan(&database)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotEmpty(t, database)
|
||||
|
||||
return testError
|
||||
})
|
||||
|
||||
assert.Equal(t, testError, resultErr)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user