@@ -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).
110110func (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.
145147func (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).
236212func (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.
300256func (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.
338286func (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.
400327func (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.
442360func (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.
586463func (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.
616478func (m * Manager ) buildCBTFrontend (ctx context.Context , force bool ) error {
0 commit comments