Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/sley/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func main() {
}

func runCLI(args []string) error {
cfg, err := config.LoadConfigFn()
cfg, err := config.LoadConfig()
if err != nil {
return err
}
Expand All @@ -37,7 +37,7 @@ func runCLI(args []string) error {
registry := plugins.NewPluginRegistry()
plugins.RegisterBuiltinPlugins(cfg, registry)

if err := hooks.LoadPreReleaseHooksFromConfigFn(cfg); err != nil {
if err := hooks.LoadPreReleaseHooksFromConfig(cfg); err != nil {
return fmt.Errorf("failed to load pre-release hooks: %w", err)
}

Expand Down
43 changes: 0 additions & 43 deletions cmd/sley/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ package main

import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"testing"

"github.com/indaco/sley/internal/config"
"github.com/indaco/sley/internal/hooks"
)

func TestRunMain_ShowVersion(t *testing.T) {
Expand Down Expand Up @@ -128,42 +124,3 @@ func TestRunMain_LoadConfigError(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
}

func TestRunMain_LoadPreReleaseHooksError(t *testing.T) {
tmp := t.TempDir()

versionPath := filepath.Join(tmp, ".version")
if err := os.WriteFile(versionPath, []byte("1.2.3\n"), 0600); err != nil {
t.Fatal(err)
}

origDir, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
if err := os.Chdir(tmp); err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
if err := os.Chdir(origDir); err != nil {
t.Fatalf("failed to restore working directory: %v", err)
}
})

// Backup and override hooks.LoadPreReleaseHooksFromConfig
originalFn := hooks.LoadPreReleaseHooksFromConfigFn
hooks.LoadPreReleaseHooksFromConfigFn = func(cfg *config.Config) error {
return fmt.Errorf("mock pre-release hook load error")
}
t.Cleanup(func() {
hooks.LoadPreReleaseHooksFromConfigFn = originalFn
})

err = runCLI([]string{"sley", "bump", "patch"})
if err == nil {
t.Fatal("expected error from LoadPreReleaseHooksFromConfig, got nil")
}
if !strings.Contains(err.Error(), "failed to load pre-release hooks") {
t.Errorf("unexpected error: %v", err)
}
}
6 changes: 2 additions & 4 deletions internal/clix/clix.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ import (
"github.com/urfave/cli/v3"
)

var FromCommandFn = fromCommand

// fromCommand extracts the --path and --strict flags from a cli.Command,
// FromCommand extracts the --path and --strict flags from a cli.Command,
// and passes them to GetOrInitVersionFile.
func fromCommand(cmd *cli.Command) (bool, error) {
func FromCommand(cmd *cli.Command) (bool, error) {
return GetOrInitVersionFile(cmd.String("path"), cmd.Bool("strict"))
}

Expand Down
4 changes: 2 additions & 2 deletions internal/clix/clix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func TestFromCommand(t *testing.T) {
cfg := &config.Config{Path: tmpFile}
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{})

created, err := FromCommandFn(appCli)
created, err := FromCommand(appCli)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -106,7 +106,7 @@ func TestFromCommand(t *testing.T) {
cfg := &config.Config{Path: targetPath}
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{})

created, err := FromCommandFn(appCli)
created, err := FromCommand(appCli)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/commands/bump/auto.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func runBumpAuto(ctx context.Context, cfg *config.Config, registry *plugins.Plug
disableInfer := isNoInferFlag || (cfg != nil && cfg.Plugins != nil && !cfg.Plugins.CommitParser)

// Run pre-release hooks first (before any version operations)
if err := hooks.RunPreReleaseHooksFn(ctx, isSkipHooks); err != nil {
if err := hooks.RunPreReleaseHooks(ctx, isSkipHooks); err != nil {
return err
}

Expand Down Expand Up @@ -152,7 +152,7 @@ func determineBumpType(registry *plugins.PluginRegistry, label string, disableIn

// runSingleModuleAuto handles the single-module auto bump operation.
func runSingleModuleAuto(ctx context.Context, cmd *cli.Command, cfg *config.Config, registry *plugins.PluginRegistry, path, label, meta, since, until string, isPreserveMeta, disableInfer, skipHooks bool) error {
if _, err := clix.FromCommandFn(cmd); err != nil {
if _, err := clix.FromCommand(cmd); err != nil {
return err
}

Expand Down
105 changes: 26 additions & 79 deletions internal/commands/bump/bump_auto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/indaco/sley/internal/config"
"github.com/indaco/sley/internal/plugins"
"github.com/indaco/sley/internal/plugins/commitparser"
"github.com/indaco/sley/internal/plugins/commitparser/gitlog"
"github.com/indaco/sley/internal/plugins/tagmanager"
"github.com/indaco/sley/internal/semver"
Expand Down Expand Up @@ -308,21 +307,20 @@ func TestTryInferBumpTypeFromCommitParserPlugin_GetCommitsError(t *testing.T) {
testutils.WithMock(func() {
// Mock GetCommits to fail
originalGetCommits := gitlog.GetCommitsFn
originalParser := commitparser.GetCommitParserFn

gitlog.GetCommitsFn = func(since, until string) ([]string, error) {
return nil, fmt.Errorf("simulated gitlog error")
}
commitparser.GetCommitParserFn = func() commitparser.CommitParser {
return testutils.MockCommitParser{} // Return any parser
}

t.Cleanup(func() {
gitlog.GetCommitsFn = originalGetCommits
commitparser.GetCommitParserFn = originalParser
})
}, func() {
registry := plugins.NewPluginRegistry()
parser := testutils.MockCommitParser{}
if err := registry.RegisterCommitParser(&parser); err != nil {
t.Fatalf("failed to register parser: %v", err)
}
label := tryInferBumpTypeFromCommitParserPlugin(registry, "", "")
if label != "" {
t.Errorf("expected empty label on gitlog error, got %q", label)
Expand All @@ -337,12 +335,13 @@ func TestTryInferBumpTypeFromCommitParserPlugin_ParserError(t *testing.T) {
gitlog.GetCommitsFn = func(since, until string) ([]string, error) {
return []string{"fix: something"}, nil
}
commitparser.GetCommitParserFn = func() commitparser.CommitParser {
return testutils.MockCommitParser{Err: fmt.Errorf("parser error")}
}
},
func() {
registry := plugins.NewPluginRegistry()
parser := testutils.MockCommitParser{Err: fmt.Errorf("parser error")}
if err := registry.RegisterCommitParser(&parser); err != nil {
t.Fatalf("failed to register parser: %v", err)
}
label := tryInferBumpTypeFromCommitParserPlugin(registry, "", "")
if label != "" {
t.Errorf("expected empty label on parser error, got %q", label)
Expand Down Expand Up @@ -695,56 +694,36 @@ func TestGetNextVersion(t *testing.T) {
/* ------------------------------------------------------------------------- */

func TestBumpAuto_CallsCreateTagAfterBump_WithEnabledTagManager(t *testing.T) {
// This test verifies that createTagAfterBump is called when tag manager is enabled
// by testing the function directly with the "auto" bump type parameter
version := semver.SemVersion{Major: 99, Minor: 88, Patch: 77}

// Save original function and restore after test
origGetTagManagerFn := tagmanager.GetTagManagerFn
defer func() { tagmanager.GetTagManagerFn = origGetTagManagerFn }()

// Create an enabled tag manager plugin
plugin := tagmanager.NewTagManager(&tagmanager.Config{
Enabled: true,
AutoCreate: true,
Prefix: "v",
Annotate: true,
})
tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return plugin }

registry := plugins.NewPluginRegistry()
if err := registry.RegisterTagManager(plugin); err != nil {
t.Fatalf("failed to register tag manager: %v", err)
}

// Call createTagAfterBump directly with "auto" bump type
// This is the call that runSingleModuleAuto makes at the end
err := createTagAfterBump(registry, version, "auto")

// The test environment may have various outcomes depending on git state
// The important thing is that the function is called and attempts tag creation
if err != nil {
errStr := err.Error()
// These are acceptable errors when running in a test environment
if !strings.Contains(errStr, "failed to create tag") && !strings.Contains(errStr, "already exists") {
t.Fatalf("expected tag creation error, tag exists error, or no error, got: %v", err)
if !strings.Contains(errStr, "failed to create tag") && !strings.Contains(errStr, "already exists") && !strings.Contains(errStr, "failed to commit") {
t.Fatalf("expected tag creation error, tag exists error, commit error, or no error, got: %v", err)
}
}
}

func TestBumpAuto_EndToEnd_WithMockTagManager(t *testing.T) {
// This test verifies the full bump auto flow with a mock tag manager
// that tracks whether CreateTag is called
tmpDir := t.TempDir()
versionPath := filepath.Join(tmpDir, ".version")
testutils.WriteTempVersionFile(t, tmpDir, "1.2.3")

// Save original function and restore after test
origGetTagManagerFn := tagmanager.GetTagManagerFn
defer func() { tagmanager.GetTagManagerFn = origGetTagManagerFn }()

// Create a mock that tracks calls - note: createTagAfterBump uses type assertion
// to *tagmanager.TagManagerPlugin, so mocks will be treated as disabled
// We use this to verify the flow works when tag manager returns nil for registry
tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return nil }

cfg := &config.Config{Path: versionPath}
registry := plugins.NewPluginRegistry()
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, registry)})
Expand All @@ -757,7 +736,6 @@ func TestBumpAuto_EndToEnd_WithMockTagManager(t *testing.T) {
t.Fatalf("expected no error, got: %v", err)
}

// Verify the version was bumped
got := testutils.ReadTempVersionFile(t, tmpDir)
want := "1.2.4"
if got != want {
Expand All @@ -770,16 +748,10 @@ func TestBumpAuto_SkipsTagCreation_WhenTagManagerDisabled(t *testing.T) {
versionPath := filepath.Join(tmpDir, ".version")
testutils.WriteTempVersionFile(t, tmpDir, "1.2.3")

// Save original function and restore after test
origGetTagManagerFn := tagmanager.GetTagManagerFn
defer func() { tagmanager.GetTagManagerFn = origGetTagManagerFn }()

// Create a disabled tag manager plugin
plugin := tagmanager.NewTagManager(&tagmanager.Config{
Enabled: false,
AutoCreate: false,
})
tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return plugin }

cfg := &config.Config{Path: versionPath}
registry := plugins.NewPluginRegistry()
Expand Down Expand Up @@ -808,13 +780,6 @@ func TestBumpAuto_SkipsTagCreation_WhenNoTagManagerRegistered(t *testing.T) {
versionPath := filepath.Join(tmpDir, ".version")
testutils.WriteTempVersionFile(t, tmpDir, "1.2.3-alpha.1")

// Save original function and restore after test
origGetTagManagerFn := tagmanager.GetTagManagerFn
defer func() { tagmanager.GetTagManagerFn = origGetTagManagerFn }()

// No tag manager registered
tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return nil }

cfg := &config.Config{Path: versionPath}
registry := plugins.NewPluginRegistry()
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, registry)})
Expand All @@ -838,35 +803,24 @@ func TestBumpAuto_TagCreatedWithCorrectParameters(t *testing.T) {
version := semver.SemVersion{Major: 1, Minor: 2, Patch: 4}

t.Run("calls createTagAfterBump with auto bump type", func(t *testing.T) {
// Save original and restore after test
origGetTagManagerFn := tagmanager.GetTagManagerFn
defer func() { tagmanager.GetTagManagerFn = origGetTagManagerFn }()

// Create enabled tag manager
plugin := tagmanager.NewTagManager(&tagmanager.Config{
Enabled: true,
AutoCreate: true,
Prefix: "v",
})
tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return plugin }

registry := plugins.NewPluginRegistry()
// Note: createTagAfterBump checks for *TagManagerPlugin type assertion
// When using a real plugin, it will try to create a tag (which fails without git)
if err := registry.RegisterTagManager(plugin); err != nil {
t.Fatalf("failed to register tag manager: %v", err)
}
err := createTagAfterBump(registry, version, "auto")

// In test environment without git, we expect a tag creation error
if err != nil && !strings.Contains(err.Error(), "failed to create tag") {
if err != nil && !strings.Contains(err.Error(), "failed to create tag") && !strings.Contains(err.Error(), "failed to commit") {
t.Errorf("unexpected error type: %v", err)
}
})

t.Run("returns nil when tag manager is nil", func(t *testing.T) {
origGetTagManagerFn := tagmanager.GetTagManagerFn
defer func() { tagmanager.GetTagManagerFn = origGetTagManagerFn }()

tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return nil }

registry := plugins.NewPluginRegistry()
err := createTagAfterBump(registry, version, "auto")
if err != nil {
Expand All @@ -875,16 +829,15 @@ func TestBumpAuto_TagCreatedWithCorrectParameters(t *testing.T) {
})

t.Run("returns nil when tag manager is disabled", func(t *testing.T) {
origGetTagManagerFn := tagmanager.GetTagManagerFn
defer func() { tagmanager.GetTagManagerFn = origGetTagManagerFn }()

plugin := tagmanager.NewTagManager(&tagmanager.Config{
Enabled: false,
AutoCreate: false,
})
tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return plugin }

registry := plugins.NewPluginRegistry()
if err := registry.RegisterTagManager(plugin); err != nil {
t.Fatalf("failed to register tag manager: %v", err)
}
err := createTagAfterBump(registry, version, "auto")
if err != nil {
t.Errorf("expected nil error when tag manager is disabled, got: %v", err)
Expand All @@ -897,19 +850,16 @@ func TestBumpAuto_TagCreation_OnPreReleasePromotion(t *testing.T) {
versionPath := filepath.Join(tmpDir, ".version")
testutils.WriteTempVersionFile(t, tmpDir, "2.0.0-rc.1")

// Save original function and restore after test
origGetTagManagerFn := tagmanager.GetTagManagerFn
defer func() { tagmanager.GetTagManagerFn = origGetTagManagerFn }()

// Create a disabled tag manager to verify bump succeeds without tag creation
plugin := tagmanager.NewTagManager(&tagmanager.Config{
Enabled: false,
AutoCreate: false,
})
tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return plugin }

cfg := &config.Config{Path: versionPath}
registry := plugins.NewPluginRegistry()
if err := registry.RegisterTagManager(plugin); err != nil {
t.Fatalf("failed to register tag manager: %v", err)
}
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, registry)})

err := appCli.Run(context.Background(), []string{
Expand All @@ -932,28 +882,25 @@ func TestBumpAuto_InferredMinorBump_WithTagManager(t *testing.T) {
versionPath := filepath.Join(tmpDir, ".version")
testutils.WriteTempVersionFile(t, tmpDir, "1.0.0")

// Save and restore original functions
origGetTagManagerFn := tagmanager.GetTagManagerFn
originalInfer := tryInferBumpTypeFromCommitParserPluginFn
defer func() {
tagmanager.GetTagManagerFn = origGetTagManagerFn
tryInferBumpTypeFromCommitParserPluginFn = originalInfer
}()

// Mock inference to return "minor"
tryInferBumpTypeFromCommitParserPluginFn = func(registry *plugins.PluginRegistry, since, until string) string {
return "minor"
}

// Create a disabled tag manager (to avoid git dependency in tests)
plugin := tagmanager.NewTagManager(&tagmanager.Config{
Enabled: false,
AutoCreate: false,
})
tagmanager.GetTagManagerFn = func() tagmanager.TagManager { return plugin }

cfg := &config.Config{Path: versionPath, Plugins: &config.PluginConfig{CommitParser: true}}
registry := plugins.NewPluginRegistry()
if err := registry.RegisterTagManager(plugin); err != nil {
t.Fatalf("failed to register tag manager: %v", err)
}
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, registry)})

err := appCli.Run(context.Background(), []string{
Expand Down
Loading