Skip to content

Commit 97623dc

Browse files
authored
feat(pre): add multi-module support for pre and bump pre commands (#191)
1 parent 18330d5 commit 97623dc

File tree

5 files changed

+94
-41
lines changed

5 files changed

+94
-41
lines changed

internal/cli/cli.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func New(cfg *config.Config, registry *plugins.PluginRegistry) *urfavecli.Comman
6262
show.Run(cfg),
6363
set.Run(cfg),
6464
bump.Run(cfg, registry),
65-
pre.Run(cfg),
65+
pre.Run(cfg, registry),
6666
doctor.Run(cfg),
6767
tag.Run(cfg),
6868
changelog.Run(cfg),

internal/commands/bump/pre.go

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,44 @@ import (
44
"context"
55
"fmt"
66

7+
"github.com/indaco/sley/internal/cliflags"
78
"github.com/indaco/sley/internal/clix"
89
"github.com/indaco/sley/internal/config"
910
"github.com/indaco/sley/internal/hooks"
11+
"github.com/indaco/sley/internal/operations"
1012
"github.com/indaco/sley/internal/plugins"
1113
"github.com/indaco/sley/internal/semver"
1214
"github.com/urfave/cli/v3"
1315
)
1416

1517
// preCmd returns the "pre" subcommand for incrementing pre-release versions.
1618
func preCmd(cfg *config.Config, registry *plugins.PluginRegistry) *cli.Command {
19+
flags := []cli.Flag{
20+
&cli.StringFlag{
21+
Name: "label",
22+
Aliases: []string{"l"},
23+
Usage: "Pre-release label (e.g., alpha, beta, rc). If omitted, increments existing pre-release",
24+
},
25+
&cli.StringFlag{
26+
Name: "meta",
27+
Usage: "Optional build metadata",
28+
},
29+
&cli.BoolFlag{
30+
Name: "preserve-meta",
31+
Usage: "Preserve existing build metadata when bumping",
32+
},
33+
&cli.BoolFlag{
34+
Name: "skip-hooks",
35+
Usage: "Skip pre-release hooks",
36+
},
37+
}
38+
flags = append(flags, cliflags.MultiModuleFlags()...)
39+
1740
return &cli.Command{
1841
Name: "pre",
1942
Usage: "Increment pre-release version (e.g., rc.1 -> rc.2)",
20-
UsageText: "sley bump pre [--label name] [--meta data] [--preserve-meta] [--skip-hooks]",
21-
Flags: []cli.Flag{
22-
&cli.StringFlag{
23-
Name: "label",
24-
Aliases: []string{"l"},
25-
Usage: "Pre-release label (e.g., alpha, beta, rc). If omitted, increments existing pre-release",
26-
},
27-
&cli.BoolFlag{
28-
Name: "skip-hooks",
29-
Usage: "Skip pre-release hooks",
30-
},
31-
},
43+
UsageText: "sley bump pre [--label name] [--meta data] [--preserve-meta] [--skip-hooks] [--all] [--module name]",
44+
Flags: flags,
3245
Action: func(ctx context.Context, cmd *cli.Command) error {
3346
return runBumpPre(ctx, cmd, cfg, registry)
3447
},
@@ -51,11 +64,14 @@ func runBumpPre(ctx context.Context, cmd *cli.Command, cfg *config.Config, regis
5164
return err
5265
}
5366

54-
if !execCtx.IsSingleModule() {
55-
return fmt.Errorf("pre-release bump not yet supported for multi-module mode")
67+
// Handle single-module mode
68+
if execCtx.IsSingleModule() {
69+
return runSingleModulePreBump(ctx, cmd, cfg, registry, execCtx, label, meta, isPreserveMeta, isSkipHooks)
5670
}
5771

58-
return runSingleModulePreBump(ctx, cmd, cfg, registry, execCtx, label, meta, isPreserveMeta, isSkipHooks)
72+
// Handle multi-module mode
73+
// For pre-release bump, the label is used as the pre-release identifier
74+
return runMultiModuleBump(ctx, cmd, execCtx, registry, operations.BumpPre, label, meta, isPreserveMeta)
5975
}
6076

6177
// runSingleModulePreBump handles pre-release bump for single-module mode.

internal/commands/initialize/initcmd_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func TestCLI_Command_InitializeVersionFilePermissionErrors(t *testing.T) {
166166
cfg := &config.Config{Path: protectedPath}
167167
appCli := testutils.BuildCLIForTests(
168168
cfg.Path,
169-
[]*cli.Command{Run(), bump.Run(cfg, plugins.NewPluginRegistry()), pre.Run(cfg)},
169+
[]*cli.Command{Run(), bump.Run(cfg, plugins.NewPluginRegistry()), pre.Run(cfg, plugins.NewPluginRegistry())},
170170
)
171171

172172
err := appCli.Run(context.Background(), append(tt.command, "--path", protectedPath))

internal/commands/pre/precmd.go

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ import (
88

99
"github.com/indaco/sley/internal/cliflags"
1010
"github.com/indaco/sley/internal/clix"
11+
"github.com/indaco/sley/internal/commands/depsync"
1112
"github.com/indaco/sley/internal/config"
1213
"github.com/indaco/sley/internal/core"
1314
"github.com/indaco/sley/internal/operations"
15+
"github.com/indaco/sley/internal/plugins"
1416
"github.com/indaco/sley/internal/printer"
1517
"github.com/indaco/sley/internal/semver"
1618
"github.com/indaco/sley/internal/workspace"
1719
"github.com/urfave/cli/v3"
1820
)
1921

2022
// Run returns the "pre" command.
21-
func Run(cfg *config.Config) *cli.Command {
23+
func Run(cfg *config.Config, registry *plugins.PluginRegistry) *cli.Command {
2224
cmdFlags := []cli.Flag{
2325
&cli.StringFlag{
2426
Name: "label",
@@ -38,13 +40,13 @@ func Run(cfg *config.Config) *cli.Command {
3840
UsageText: "sley pre --label <label> [--inc] [--all] [--module name]",
3941
Flags: cmdFlags,
4042
Action: func(ctx context.Context, cmd *cli.Command) error {
41-
return runPreCmd(ctx, cmd, cfg)
43+
return runPreCmd(ctx, cmd, cfg, registry)
4244
},
4345
}
4446
}
4547

4648
// runPreCmd sets or increments the pre-release label.
47-
func runPreCmd(ctx context.Context, cmd *cli.Command, cfg *config.Config) error {
49+
func runPreCmd(ctx context.Context, cmd *cli.Command, cfg *config.Config, registry *plugins.PluginRegistry) error {
4850
label := cmd.String("label")
4951
isInc := cmd.Bool("inc")
5052

@@ -56,15 +58,15 @@ func runPreCmd(ctx context.Context, cmd *cli.Command, cfg *config.Config) error
5658

5759
// Handle single-module mode
5860
if execCtx.IsSingleModule() {
59-
return runSingleModulePre(execCtx.Path, label, isInc)
61+
return runSingleModulePre(execCtx.Path, label, isInc, registry)
6062
}
6163

6264
// Handle multi-module mode
63-
return runMultiModulePre(ctx, cmd, execCtx, label, isInc)
65+
return runMultiModulePre(ctx, cmd, execCtx, label, isInc, registry)
6466
}
6567

6668
// runSingleModulePre handles the single-module pre-release operation.
67-
func runSingleModulePre(path, label string, isInc bool) error {
69+
func runSingleModulePre(path, label string, isInc bool, registry *plugins.PluginRegistry) error {
6870
// Auto-initialize if file doesn't exist
6971
var version semver.SemVersion
7072
version, err := semver.ReadVersion(path)
@@ -97,11 +99,17 @@ func runSingleModulePre(path, label string, isInc bool) error {
9799
}
98100

99101
printer.PrintSuccess(fmt.Sprintf("Updated version from %s to %s", oldVersion, version.String()))
102+
103+
// Sync dependencies if configured
104+
if err := depsync.SyncDependencies(registry, version, path); err != nil {
105+
return err
106+
}
107+
100108
return nil
101109
}
102110

103111
// runMultiModulePre handles the multi-module pre-release operation.
104-
func runMultiModulePre(ctx context.Context, cmd *cli.Command, execCtx *clix.ExecutionContext, label string, isInc bool) error {
112+
func runMultiModulePre(ctx context.Context, cmd *cli.Command, execCtx *clix.ExecutionContext, label string, isInc bool, registry *plugins.PluginRegistry) error {
105113
fs := core.NewOSFileSystem()
106114
operation := operations.NewPreOperation(fs, label, isInc)
107115

@@ -145,6 +153,23 @@ func runMultiModulePre(ctx context.Context, cmd *cli.Command, execCtx *clix.Exec
145153
fmt.Println(formatter.FormatResults(results))
146154
}
147155

156+
// Sync dependencies if configured (use the first successful result's version)
157+
if !workspace.HasErrors(results) && len(results) > 0 {
158+
// Get the new version from the first successful result
159+
for _, result := range results {
160+
if result.Error == nil && result.NewVersion != "" {
161+
parsedVersion, parseErr := semver.ParseVersion(result.NewVersion)
162+
if parseErr == nil {
163+
bumpedPaths := getBumpedModulePaths(results)
164+
if syncErr := depsync.SyncDependencies(registry, parsedVersion, bumpedPaths...); syncErr != nil {
165+
return syncErr
166+
}
167+
}
168+
break
169+
}
170+
}
171+
}
172+
148173
// Return error if any failures occurred
149174
if workspace.HasErrors(results) {
150175
return fmt.Errorf("%d module(s) failed", workspace.ErrorCount(results))
@@ -153,6 +178,17 @@ func runMultiModulePre(ctx context.Context, cmd *cli.Command, execCtx *clix.Exec
153178
return nil
154179
}
155180

181+
// getBumpedModulePaths extracts the paths of successfully bumped modules.
182+
func getBumpedModulePaths(results []workspace.ExecutionResult) []string {
183+
var paths []string
184+
for _, r := range results {
185+
if r.Error == nil {
186+
paths = append(paths, r.Module.Path)
187+
}
188+
}
189+
return paths
190+
}
191+
156192
// printQuietSummary prints a minimal summary of results.
157193
func printQuietSummary(results []workspace.ExecutionResult) {
158194
success := workspace.SuccessCount(results)

internal/commands/pre/precmd_test.go

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"testing"
1111

1212
"github.com/indaco/sley/internal/config"
13+
"github.com/indaco/sley/internal/plugins"
1314
"github.com/indaco/sley/internal/semver"
1415
"github.com/indaco/sley/internal/testutils"
1516
"github.com/indaco/sley/internal/workspace"
@@ -22,7 +23,7 @@ func TestCLI_PreCommand_StaticLabel(t *testing.T) {
2223

2324
// Prepare and run the CLI command
2425
cfg := &config.Config{Path: versionPath}
25-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
26+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
2627

2728
testutils.WriteTempVersionFile(t, tmpDir, "1.2.3")
2829
testutils.RunCLITest(t, appCli, []string{"sley", "pre", "--label", "beta.1"}, tmpDir)
@@ -39,7 +40,7 @@ func TestCLI_PreCommand_Increment(t *testing.T) {
3940

4041
// Prepare and run the CLI command
4142
cfg := &config.Config{Path: versionPath}
42-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
43+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
4344

4445
testutils.RunCLITest(t, appCli, []string{"sley", "pre", "--label", "beta", "--inc"}, tmpDir)
4546
content := testutils.ReadTempVersionFile(t, tmpDir)
@@ -54,7 +55,7 @@ func TestCLI_PreCommand_AutoInitFeedback(t *testing.T) {
5455

5556
// Prepare and run the CLI command
5657
cfg := &config.Config{Path: versionPath}
57-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
58+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
5859

5960
output, err := testutils.CaptureStdout(func() {
6061
testutils.RunCLITest(t, appCli, []string{"sley", "pre", "--label", "alpha"}, tmpDir)
@@ -80,7 +81,7 @@ func TestCLI_PreCommand_InvalidVersion(t *testing.T) {
8081

8182
// Prepare and run the CLI command
8283
cfg := &config.Config{Path: defaultPath}
83-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
84+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
8485

8586
err := appCli.Run(context.Background(), []string{
8687
"sley", "pre", "--label", "alpha", "--path", customPath,
@@ -110,7 +111,7 @@ func TestCLI_PreCommand_SaveVersionFails(t *testing.T) {
110111

111112
// Prepare and run the CLI command
112113
cfg := &config.Config{Path: versionPath}
113-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
114+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
114115

115116
err := appCli.Run(context.Background(), []string{
116117
"sley", "pre", "--label", "rc", "--path", versionPath,
@@ -151,7 +152,7 @@ func TestCLI_PreCommand_StaticLabel_Variants(t *testing.T) {
151152
versionPath := filepath.Join(tmpDir, ".version")
152153

153154
cfg := &config.Config{Path: versionPath}
154-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
155+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
155156

156157
tests := []struct {
157158
name string
@@ -183,7 +184,7 @@ func TestCLI_PreCommand_Increment_Variants(t *testing.T) {
183184
versionPath := filepath.Join(tmpDir, ".version")
184185

185186
cfg := &config.Config{Path: versionPath}
186-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
187+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
187188

188189
tests := []struct {
189190
name string
@@ -216,7 +217,7 @@ func TestCLI_PreCommand_LabelSwitchWithIncrement(t *testing.T) {
216217
versionPath := filepath.Join(tmpDir, ".version")
217218

218219
cfg := &config.Config{Path: versionPath}
219-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
220+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
220221

221222
tests := []struct {
222223
name string
@@ -246,7 +247,7 @@ func TestCLI_PreCommand_EdgeCases(t *testing.T) {
246247
versionPath := filepath.Join(tmpDir, ".version")
247248

248249
cfg := &config.Config{Path: versionPath}
249-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
250+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
250251

251252
tests := []struct {
252253
name string
@@ -295,7 +296,7 @@ func TestCLI_PreCommand_PermissionErrors(t *testing.T) {
295296
versionPath := filepath.Join(protectedDir, ".version")
296297

297298
cfg := &config.Config{Path: versionPath}
298-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
299+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
299300

300301
err := appCli.Run(context.Background(), []string{
301302
"sley", "pre", "--label", "alpha", "--path", versionPath,
@@ -341,7 +342,7 @@ func TestCLI_PreCommand_MultiModule_All(t *testing.T) {
341342
},
342343
}
343344

344-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
345+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
345346

346347
// Test with --all flag
347348
output, err := testutils.CaptureStdout(func() {
@@ -401,7 +402,7 @@ func TestCLI_PreCommand_MultiModule_Increment(t *testing.T) {
401402
},
402403
}
403404

404-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
405+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
405406

406407
// Test with --all and --inc flags
407408
output, err := testutils.CaptureStdout(func() {
@@ -459,7 +460,7 @@ func TestCLI_PreCommand_MultiModule_Specific(t *testing.T) {
459460
},
460461
}
461462

462-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
463+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
463464

464465
// Test with --module flag to target specific module
465466
testutils.RunCLITest(t, appCli, []string{"sley", "pre", "--label", "alpha", "--module", "module-a"}, tmpDir)
@@ -507,7 +508,7 @@ func TestCLI_PreCommand_MultiModule_Quiet(t *testing.T) {
507508
},
508509
}
509510

510-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
511+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
511512

512513
// Test with --quiet flag
513514
output, err := testutils.CaptureStdout(func() {
@@ -562,7 +563,7 @@ func TestCLI_PreCommand_MultiModule_JSONFormat(t *testing.T) {
562563
},
563564
}
564565

565-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
566+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
566567

567568
// Test with --format json
568569
output, err := testutils.CaptureStdout(func() {
@@ -614,7 +615,7 @@ func TestCLI_PreCommand_MultiModule_Parallel(t *testing.T) {
614615
},
615616
}
616617

617-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
618+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
618619

619620
// Test with --parallel flag
620621
testutils.RunCLITest(t, appCli, []string{"sley", "pre", "--label", "alpha", "--all", "--parallel"}, tmpDir)
@@ -660,7 +661,7 @@ func TestCLI_PreCommand_MultiModule_TextFormat(t *testing.T) {
660661
},
661662
}
662663

663-
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg)})
664+
appCli := testutils.BuildCLIForTests(cfg.Path, []*cli.Command{Run(cfg, plugins.NewPluginRegistry())})
664665

665666
// Test with --format text
666667
output, err := testutils.CaptureStdout(func() {

0 commit comments

Comments
 (0)