Skip to content

Commit 73255cb

Browse files
committed
refactor(builder): delegate all *WithResult methods to avoid duplication
Replace duplicated build logic in BuildXatuCBT, BuildCBT, BuildCBTAPI, BuildLabBackend, BuildLabFrontend, GenerateXatuCBTProtos and GenerateProtos with single-line calls to their *WithResult counterparts. This removes ~150 lines of repeated code and keeps the public API unchanged.
1 parent f9e54e6 commit 73255cb

File tree

1 file changed

+15
-153
lines changed

1 file changed

+15
-153
lines changed

pkg/builder/manager.go

Lines changed: 15 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ func (m *Manager) BuildAll(ctx context.Context, force bool) error {
108108

109109
// BuildXatuCBT builds only the xatu-cbt binary (needed for infrastructure startup).
110110
func (m *Manager) BuildXatuCBT(ctx context.Context, force bool) error {
111-
return m.buildXatuCBT(ctx, force)
111+
result := m.BuildXatuCBTWithResult(ctx, force)
112+
113+
return result.Error
112114
}
113115

114116
// BuildXatuCBTWithResult builds xatu-cbt binary and returns BuildResult.
@@ -143,35 +145,9 @@ func (m *Manager) XatuCBTBinaryExists() bool {
143145

144146
// BuildCBT builds the cbt binary.
145147
func (m *Manager) BuildCBT(ctx context.Context, force bool) error {
146-
binary := filepath.Join(m.cfg.Repos.CBT, "bin", "cbt")
147-
148-
if !force && m.binaryExists(binary) {
149-
m.log.WithField("repo", "cbt").Info("binary exists, skipping build")
150-
151-
return nil
152-
}
153-
154-
m.log.WithField("repo", "cbt").Info("building project")
155-
156-
// Build CBT frontend first (required for embedding in binary)
157-
if err := m.buildCBTFrontend(ctx, force); err != nil {
158-
return fmt.Errorf("failed to build CBT frontend: %w", err)
159-
}
160-
161-
// CBT doesn't have a Makefile build target, build directly
162-
binDir := filepath.Join(m.cfg.Repos.CBT, "bin")
163-
if err := os.MkdirAll(binDir, 0755); err != nil {
164-
return fmt.Errorf("failed to create bin directory: %w", err)
165-
}
166-
167-
cmd := exec.CommandContext(ctx, "go", "build", "-o", binary, ".")
168-
cmd.Dir = m.cfg.Repos.CBT
148+
result := m.BuildCBTWithResult(ctx, force)
169149

170-
if err := executil.RunCmd(cmd, m.verbose); err != nil {
171-
return fmt.Errorf("go build failed: %w", err)
172-
}
173-
174-
return nil
150+
return result.Error
175151
}
176152

177153
// BuildCBTWithResult builds the cbt binary and returns BuildResult.
@@ -234,29 +210,9 @@ func (m *Manager) BuildCBTWithResult(ctx context.Context, force bool) *diagnosti
234210
// BuildCBTAPI builds cbt-api with proto generation
235211
// Proto generation MUST happen first (explicit dependency in graph).
236212
func (m *Manager) BuildCBTAPI(ctx context.Context, force bool) error {
237-
// Step 1: Generate protos
238-
if err := m.GenerateProtos(ctx); err != nil {
239-
return err
240-
}
241-
242-
// Step 2: Build cbt-api binary
243-
binary := filepath.Join(m.cfg.Repos.CBTAPI, "bin", "server")
213+
result := m.BuildCBTAPIWithResult(ctx, force)
244214

245-
if !force && m.binaryExists(binary) {
246-
m.log.WithField("repo", "cbt-api").Info("binary exists, skipping build")
247-
248-
return nil
249-
}
250-
251-
m.log.WithField("repo", "cbt-api").Info("building project")
252-
253-
// Generate OpenAPI and other code (requires proto to be run first)
254-
if err := m.runMake(ctx, m.cfg.Repos.CBTAPI, "generate"); err != nil {
255-
return fmt.Errorf("make generate failed: %w", err)
256-
}
257-
258-
// Build the binary
259-
return m.runMake(ctx, m.cfg.Repos.CBTAPI, "build-binary")
215+
return result.Error
260216
}
261217

262218
// BuildCBTAPIWithResult builds cbt-api with proto generation and returns BuildResult.
@@ -298,17 +254,9 @@ func (m *Manager) BuildCBTAPIWithResult(ctx context.Context, force bool) *diagno
298254

299255
// BuildLabBackend builds lab-backend binary.
300256
func (m *Manager) BuildLabBackend(ctx context.Context, force bool) error {
301-
binary := filepath.Join(m.cfg.Repos.LabBackend, "bin", "lab-backend")
302-
303-
if !force && m.binaryExists(binary) {
304-
m.log.WithField("repo", "lab-backend").Info("binary exists, skipping build")
305-
306-
return nil
307-
}
257+
result := m.BuildLabBackendWithResult(ctx, force)
308258

309-
m.log.WithField("repo", "lab-backend").Info("building project")
310-
311-
return m.runMake(ctx, m.cfg.Repos.LabBackend, "build")
259+
return result.Error
312260
}
313261

314262
// BuildLabBackendWithResult builds lab-backend binary and returns BuildResult.
@@ -336,30 +284,9 @@ func (m *Manager) BuildLabBackendWithResult(ctx context.Context, force bool) *di
336284

337285
// BuildLabFrontend regenerates frontend API types from cbt-api OpenAPI spec.
338286
func (m *Manager) BuildLabFrontend(ctx context.Context) error {
339-
m.log.WithField("repo", "lab").Info("regenerating API types from cbt-api")
340-
341-
// Get the first enabled network to use for the OpenAPI endpoint
342-
networks := m.cfg.EnabledNetworks()
343-
if len(networks) == 0 {
344-
return fmt.Errorf("no networks enabled - cannot determine cbt-api port")
345-
}
287+
result := m.BuildLabFrontendWithResult(ctx)
346288

347-
// Use the first enabled network's cbt-api port
348-
cbtAPIPort := m.cfg.GetCBTAPIPort(networks[0].Name)
349-
350-
// Construct OpenAPI URL using cbt-api port
351-
openapiURL := fmt.Sprintf("http://localhost:%d/openapi.yaml", cbtAPIPort)
352-
353-
cmd := exec.CommandContext(ctx, "pnpm", "run", "generate:api")
354-
cmd.Dir = m.cfg.Repos.Lab
355-
356-
cmd.Env = append(os.Environ(), fmt.Sprintf("OPENAPI_INPUT=%s", openapiURL))
357-
358-
if err := executil.RunCmd(cmd, m.verbose); err != nil {
359-
return fmt.Errorf("pnpm run generate:api failed: %w", err)
360-
}
361-
362-
return nil
289+
return result.Error
363290
}
364291

365292
// BuildLabFrontendWithResult regenerates frontend API types and returns BuildResult.
@@ -398,18 +325,9 @@ func (m *Manager) BuildLabFrontendWithResult(ctx context.Context) *diagnostic.Bu
398325

399326
// GenerateXatuCBTProtos generates protobuf files for xatu-cbt.
400327
func (m *Manager) GenerateXatuCBTProtos(ctx context.Context) error {
401-
m.log.WithField("repo", "xatu-cbt").Info("generating protos")
328+
result := m.GenerateXatuCBTProtosWithResult(ctx)
402329

403-
// Clean generated proto files before regenerating to avoid stale files
404-
if err := m.CleanXatuCBTProtos(); err != nil {
405-
m.log.WithError(err).Warn("failed to clean xatu-cbt protos, continuing anyway")
406-
}
407-
408-
if err := m.runMake(ctx, m.cfg.Repos.XatuCBT, "proto"); err != nil {
409-
return fmt.Errorf("failed to generate xatu-cbt protos: %w", err)
410-
}
411-
412-
return nil
330+
return result.Error
413331
}
414332

415333
// GenerateXatuCBTProtosWithResult generates protobuf files for xatu-cbt and returns BuildResult.
@@ -440,38 +358,9 @@ func (m *Manager) CleanXatuCBTProtos() error {
440358

441359
// GenerateProtos generates protobuf files for cbt-api.
442360
func (m *Manager) GenerateProtos(ctx context.Context) error {
443-
// Generate cbt-api protos (only for first network, they're network-agnostic)
444-
// We'll use mainnet as the source for table schemas
445-
network := m.cfg.EnabledNetworks()[0]
446-
447-
m.log.WithFields(logrus.Fields{
448-
"repo": "cbt-api",
449-
"network": network.Name,
450-
}).Info("generating protos")
451-
452-
// Clean generated files before regenerating to avoid stale files
453-
if err := m.CleanCBTAPIGenerated(); err != nil {
454-
m.log.WithError(err).Warn("failed to clean cbt-api generated files, continuing anyway")
455-
}
456-
457-
// Use the generated config file
458-
configPath := filepath.Join(".xcli", "configs", fmt.Sprintf("cbt-api-%s.yaml", network.Name))
459-
460-
absConfigPath, err := filepath.Abs(configPath)
461-
if err != nil {
462-
return fmt.Errorf("failed to get absolute config path: %w", err)
463-
}
361+
result := m.GenerateProtosWithResult(ctx)
464362

465-
cmd := exec.CommandContext(ctx, "make", "proto")
466-
cmd.Dir = m.cfg.Repos.CBTAPI
467-
468-
cmd.Env = append(os.Environ(), fmt.Sprintf("CONFIG_FILE=%s", absConfigPath))
469-
470-
if err := executil.RunCmd(cmd, m.verbose); err != nil {
471-
return fmt.Errorf("failed to generate cbt-api protos: %w", err)
472-
}
473-
474-
return nil
363+
return result.Error
475364
}
476365

477366
// GenerateProtosWithResult generates protobuf files for cbt-api and returns BuildResult.
@@ -570,18 +459,6 @@ func (m *Manager) dirExists(path string) bool {
570459
return info.IsDir()
571460
}
572461

573-
// runMake runs make with a target in a directory.
574-
func (m *Manager) runMake(ctx context.Context, dir string, target string) error {
575-
cmd := exec.CommandContext(ctx, "make", target)
576-
cmd.Dir = dir
577-
578-
if err := executil.RunCmd(cmd, m.verbose); err != nil {
579-
return fmt.Errorf("make %s failed: %w", target, err)
580-
}
581-
582-
return nil
583-
}
584-
585462
// runMakeWithResult runs make with a target and returns BuildResult.
586463
func (m *Manager) runMakeWithResult(
587464
ctx context.Context,
@@ -596,21 +473,6 @@ func (m *Manager) runMakeWithResult(
596473
return executil.RunCmdWithResult(cmd, m.verbose, phase, service)
597474
}
598475

599-
// buildXatuCBT builds the xatu-cbt binary (Phase 0 only, NOT in BuildAll).
600-
func (m *Manager) buildXatuCBT(ctx context.Context, force bool) error {
601-
binary := filepath.Join(m.cfg.Repos.XatuCBT, "bin", "xatu-cbt")
602-
603-
if !force && m.binaryExists(binary) {
604-
m.log.WithField("repo", "xatu-cbt").Info("binary exists, skipping build")
605-
606-
return nil
607-
}
608-
609-
m.log.WithField("repo", "xatu-cbt").Info("building project")
610-
611-
return m.runMake(ctx, m.cfg.Repos.XatuCBT, "build")
612-
}
613-
614476
// buildCBTFrontend builds the CBT frontend (React/Vite app).
615477
// The frontend is embedded into the CBT binary via go:embed, so it must be built before the Go binary.
616478
func (m *Manager) buildCBTFrontend(ctx context.Context, force bool) error {

0 commit comments

Comments
 (0)