refactor(cmd): use factories instead of global cobra command structs

This enables us to create new commands for e2e tests.
This commit is contained in:
Julian Tölle 2025-06-15 16:27:31 +02:00
parent fc1ee70c28
commit 94c1aeed55
4 changed files with 111 additions and 95 deletions

View file

@ -7,21 +7,23 @@ import (
"os/signal" "os/signal"
"runtime/debug" "runtime/debug"
"syscall" "syscall"
"time"
"github.com/lmittmann/tint"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var logger *slog.Logger func NewRootCmd() *cobra.Command {
var cmd = &cobra.Command{
var rootCmd = &cobra.Command{
Use: "rp", Use: "rp",
Short: "", Short: "",
Long: ``, Long: ``,
Version: version(), Version: version(),
SilenceUsage: true, // Makes it harder to find the actual error SilenceUsage: true, // Makes it harder to find the actual error
SilenceErrors: true, // We log manually with slog SilenceErrors: true, // We log manually with slog
}
cmd.AddCommand(newRunCommand())
return cmd
} }
func version() string { func version() string {
@ -66,24 +68,13 @@ func Execute() {
// Make sure to stop listening on signals after receiving the first signal to hand control of the signal back // Make sure to stop listening on signals after receiving the first signal to hand control of the signal back
// to the runtime. The Go runtime implements a "force shutdown" if the signal is received again. // to the runtime. The Go runtime implements a "force shutdown" if the signal is received again.
<-ctx.Done() <-ctx.Done()
logger.InfoContext(ctx, "Received shutdown signal, stopping...") slog.InfoContext(ctx, "Received shutdown signal, stopping...")
stop() stop()
}() }()
err := rootCmd.ExecuteContext(ctx) err := NewRootCmd().ExecuteContext(ctx)
if err != nil { if err != nil {
logger.ErrorContext(ctx, err.Error()) slog.ErrorContext(ctx, err.Error())
os.Exit(1) os.Exit(1)
} }
} }
func init() {
logger = slog.New(
tint.NewHandler(os.Stderr, &tint.Options{
Level: slog.LevelDebug,
TimeFormat: time.RFC3339,
}),
)
slog.SetDefault(logger)
}

View file

@ -2,6 +2,7 @@ package cmd
import ( import (
"fmt" "fmt"
"log/slog"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -11,35 +12,25 @@ import (
"github.com/apricote/releaser-pleaser/internal/forge" "github.com/apricote/releaser-pleaser/internal/forge"
"github.com/apricote/releaser-pleaser/internal/forge/github" "github.com/apricote/releaser-pleaser/internal/forge/github"
"github.com/apricote/releaser-pleaser/internal/forge/gitlab" "github.com/apricote/releaser-pleaser/internal/forge/gitlab"
"github.com/apricote/releaser-pleaser/internal/log"
"github.com/apricote/releaser-pleaser/internal/updater" "github.com/apricote/releaser-pleaser/internal/updater"
"github.com/apricote/releaser-pleaser/internal/versioning" "github.com/apricote/releaser-pleaser/internal/versioning"
) )
var runCmd = &cobra.Command{ func newRunCommand() *cobra.Command {
Use: "run", var (
RunE: run,
}
var (
flagForge string flagForge string
flagBranch string flagBranch string
flagOwner string flagOwner string
flagRepo string flagRepo string
flagExtraFiles string flagExtraFiles string
) )
func init() { var cmd = &cobra.Command{
rootCmd.AddCommand(runCmd) Use: "run",
RunE: func(cmd *cobra.Command, _ []string) error {
runCmd.PersistentFlags().StringVar(&flagForge, "forge", "", "")
runCmd.PersistentFlags().StringVar(&flagBranch, "branch", "main", "")
runCmd.PersistentFlags().StringVar(&flagOwner, "owner", "", "")
runCmd.PersistentFlags().StringVar(&flagRepo, "repo", "", "")
runCmd.PersistentFlags().StringVar(&flagExtraFiles, "extra-files", "", "")
}
func run(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context() ctx := cmd.Context()
logger := log.GetLogger(cmd.ErrOrStderr())
var err error var err error
@ -65,7 +56,7 @@ func run(cmd *cobra.Command, _ []string) error {
Path: fmt.Sprintf("%s/%s", flagOwner, flagRepo), Path: fmt.Sprintf("%s/%s", flagOwner, flagRepo),
}) })
if err != nil { if err != nil {
logger.ErrorContext(ctx, "failed to create client", "err", err) slog.ErrorContext(ctx, "failed to create client", "err", err)
return fmt.Errorf("failed to create gitlab client: %w", err) return fmt.Errorf("failed to create gitlab client: %w", err)
} }
case "github": case "github":
@ -92,6 +83,16 @@ func run(cmd *cobra.Command, _ []string) error {
) )
return releaserPleaser.Run(ctx) return releaserPleaser.Run(ctx)
},
}
cmd.PersistentFlags().StringVar(&flagForge, "forge", "", "")
cmd.PersistentFlags().StringVar(&flagBranch, "branch", "main", "")
cmd.PersistentFlags().StringVar(&flagOwner, "owner", "", "")
cmd.PersistentFlags().StringVar(&flagRepo, "repo", "", "")
cmd.PersistentFlags().StringVar(&flagExtraFiles, "extra-files", "", "")
return cmd
} }
func parseExtraFiles(input string) []string { func parseExtraFiles(input string) []string {

View file

@ -2,6 +2,7 @@ package main
import ( import (
"github.com/apricote/releaser-pleaser/cmd/rp/cmd" "github.com/apricote/releaser-pleaser/cmd/rp/cmd"
_ "github.com/apricote/releaser-pleaser/internal/log"
) )
func main() { func main() {

23
internal/log/log.go Normal file
View file

@ -0,0 +1,23 @@
package log
import (
"io"
"log/slog"
"os"
"time"
"github.com/lmittmann/tint"
)
func GetLogger(w io.Writer) *slog.Logger {
return slog.New(
tint.NewHandler(w, &tint.Options{
Level: slog.LevelDebug,
TimeFormat: time.RFC3339,
}),
)
}
func init() {
slog.SetDefault(GetLogger(os.Stderr))
}