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
9 changes: 2 additions & 7 deletions pkg/blueprint/blueprint_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (b *BaseBlueprintHandler) Initialize() error {
}

// LoadConfig reads blueprint configuration from blueprint.yaml file.
// Only loads existing blueprint.yaml files - no templating or generation.
// Returns an error if blueprint.yaml does not exist.
// Template processing is now handled by the pkg/template package.
func (b *BaseBlueprintHandler) LoadConfig() error {
configRoot, err := b.configHandler.GetConfigRoot()
Expand All @@ -132,12 +132,7 @@ func (b *BaseBlueprintHandler) LoadConfig() error {

yamlPath := filepath.Join(configRoot, "blueprint.yaml")
if _, err := b.shims.Stat(yamlPath); err != nil {
// No blueprint.yaml exists - use default blueprint
context := b.configHandler.GetContext()
b.blueprint = *DefaultBlueprint.DeepCopy()
b.blueprint.Metadata.Name = context
b.blueprint.Metadata.Description = fmt.Sprintf("This blueprint outlines resources in the %s context", context)
return nil
return fmt.Errorf("blueprint.yaml not found at %s", yamlPath)
}

yamlData, err := b.shims.ReadFile(yamlPath)
Expand Down
33 changes: 12 additions & 21 deletions pkg/blueprint/blueprint_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -640,18 +640,14 @@ func TestBlueprintHandler_LoadConfig(t *testing.T) {
// When loading the config
err := handler.LoadConfig()

// Then no error should be returned
if err != nil {
t.Errorf("Expected no error, got %v", err)
// Then an error should be returned since blueprint.yaml doesn't exist
if err == nil {
t.Errorf("Expected error when blueprint.yaml doesn't exist, got nil")
}

// And the default metadata should be set correctly
metadata := handler.GetMetadata()
if metadata.Name != "local" {
t.Errorf("Expected name to be 'local', got %s", metadata.Name)
}
if metadata.Description != "This blueprint outlines resources in the local context" {
t.Errorf("Expected description to be 'This blueprint outlines resources in the local context', got %s", metadata.Description)
// And the error should indicate blueprint.yaml not found
if !strings.Contains(err.Error(), "blueprint.yaml not found") {
t.Errorf("Expected error about blueprint.yaml not found, got: %v", err)
}
})

Expand Down Expand Up @@ -812,19 +808,14 @@ func TestBlueprintHandler_LoadConfig(t *testing.T) {
// When loading the config
err := handler.LoadConfig()

// Then no error should be returned
if err != nil {
t.Errorf("Expected no error for empty evaluated jsonnet, got: %v", err)
// Then an error should be returned since blueprint.yaml doesn't exist
if err == nil {
t.Errorf("Expected error when blueprint.yaml doesn't exist, got nil")
}

// And the default metadata should be set correctly
metadata := handler.GetMetadata()
if metadata.Name != "local" {
t.Errorf("Expected blueprint name to be 'local', got: %s", metadata.Name)
}
expectedDesc := "This blueprint outlines resources in the local context"
if metadata.Description != expectedDesc {
t.Errorf("Expected description '%s', got: %s", expectedDesc, metadata.Description)
// And the error should indicate blueprint.yaml not found
if !strings.Contains(err.Error(), "blueprint.yaml not found") {
t.Errorf("Expected error about blueprint.yaml not found, got: %v", err)
}
})

Expand Down
82 changes: 49 additions & 33 deletions pkg/pipelines/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,84 +213,68 @@ func (p *InitPipeline) Initialize(injector di.Injector, ctx context.Context) err
}
}

if p.networkManager != nil {
if err := p.networkManager.Initialize(); err != nil {
return fmt.Errorf("failed to initialize network manager: %w", err)
}
}

return nil
}

// Execute runs the init pipeline, performing trusted file setup, reset token writing, context ID generation,
// configuration saving, network manager initialization, template data preparation, template processing and
// blueprint generation, blueprint loading, terraform module resolution, and final file generation.
// All component initialization is performed in Initialize(). Phases are executed in strict order.
// Execute performs initialization by setting up trusted files, writing reset tokens, generating context IDs,
// configuring defaults, saving configuration, processing templates, handling blueprints separately,
// writing blueprint files, resolving Terraform modules, and generating final output files.
func (p *InitPipeline) Execute(ctx context.Context) error {

// Phase 1: Setup & configuration
if err := p.shell.AddCurrentDirToTrustedFile(); err != nil {
return fmt.Errorf("Error adding current directory to trusted file: %w", err)
}

if _, err := p.shell.WriteResetToken(); err != nil {
return fmt.Errorf("Error writing reset token: %w", err)
}

if err := p.configHandler.GenerateContextID(); err != nil {
return fmt.Errorf("failed to generate context ID: %w", err)
}

reset := false
if resetValue := ctx.Value("reset"); resetValue != nil {
reset = resetValue.(bool)
}

// Set default configuration before saving
contextName := p.determineContextName(ctx)
if err := p.setDefaultConfiguration(ctx, contextName); err != nil {
return err
}

if err := p.saveConfiguration(reset); err != nil {
return err
}

// Network manager phase
if p.networkManager != nil {
if err := p.networkManager.Initialize(); err != nil {
return fmt.Errorf("failed to initialize network manager: %w", err)
}
}

// Phase 1: template data preparation
// Phase 2: Template processing
templateData, err := p.prepareTemplateData(ctx)
if err != nil {
return fmt.Errorf("failed to prepare template data: %w", err)
}

// Phase 2: template processing and blueprint generation
renderedData, err := p.processTemplateData(templateData)
if err != nil {
return err
}

if err := p.loadBlueprintFromTemplate(ctx, renderedData); err != nil {
// Phase 3: Blueprint handling
if err := p.handleBlueprintLoading(ctx, renderedData, reset); err != nil {
return err
}

// Phase 3: blueprint loading (fallback if no template data)
if len(renderedData) == 0 || renderedData["blueprint"] == nil {
if err := p.blueprintHandler.LoadConfig(); err != nil {
return fmt.Errorf("Error loading blueprint config: %w", err)
}
}

// Write blueprint file
if err := p.blueprintHandler.Write(reset); err != nil {
return fmt.Errorf("failed to write blueprint file: %w", err)
}

// Phase 4: terraform module resolution
// Phase 4: Terraform module resolution
for _, resolver := range p.terraformResolvers {
if err := resolver.ProcessModules(); err != nil {
return fmt.Errorf("failed to process terraform modules: %w", err)
}
}

// Phase 5: final generation
// Phase 5: Final file generation
if len(renderedData) > 0 {
for _, generator := range p.generators {
if err := generator.Generate(renderedData, reset); err != nil {
Expand All @@ -303,7 +287,6 @@ func (p *InitPipeline) Execute(ctx context.Context) error {
return err
}

// Print success message
fmt.Fprintln(os.Stderr, "Initialization successful")

return nil
Expand Down Expand Up @@ -550,6 +533,39 @@ func (p *InitPipeline) writeConfigurationFiles() error {
return nil
}

// handleBlueprintLoading manages blueprint loading logic based on reset flag and existing blueprint files.
// If reset is true, loads blueprint from template data if available.
// If reset is false, prefers existing blueprint.yaml over template data.
// Falls back to loading from existing config if no template blueprint data exists.
func (p *InitPipeline) handleBlueprintLoading(ctx context.Context, renderedData map[string]any, reset bool) error {
shouldLoadFromTemplate := false

if reset {
shouldLoadFromTemplate = true
} else {
configRoot, err := p.configHandler.GetConfigRoot()
if err != nil {
return fmt.Errorf("error getting config root: %w", err)
}
blueprintPath := filepath.Join(configRoot, "blueprint.yaml")
if _, err := p.shims.Stat(blueprintPath); err != nil {
shouldLoadFromTemplate = true
}
}

if shouldLoadFromTemplate && len(renderedData) > 0 && renderedData["blueprint"] != nil {
if err := p.loadBlueprintFromTemplate(ctx, renderedData); err != nil {
return err
}
} else {
if err := p.blueprintHandler.LoadConfig(); err != nil {
return fmt.Errorf("Error loading blueprint config: %w", err)
}
}

return nil
}

// =============================================================================
// Interface Compliance
// =============================================================================
Expand Down
Loading