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
7 changes: 4 additions & 3 deletions cmd/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"os"
"testing"

"github.com/windsorcli/cli/pkg/bundler"
Expand Down Expand Up @@ -40,7 +41,7 @@ contexts:
// Create mock artifact builder
artifactBuilder := bundler.NewMockArtifact()
artifactBuilder.InitializeFunc = func(injector di.Injector) error { return nil }
artifactBuilder.AddFileFunc = func(path string, content []byte) error { return nil }
artifactBuilder.AddFileFunc = func(path string, content []byte, mode os.FileMode) error { return nil }
artifactBuilder.CreateFunc = func(outputPath string, tag string) (string, error) {
if tag != "" {
return "test-v1.0.0.tar.gz", nil
Expand Down Expand Up @@ -351,7 +352,7 @@ func TestBundleCmd(t *testing.T) {
// Create a fresh artifact builder to avoid state contamination
freshArtifactBuilder := bundler.NewMockArtifact()
freshArtifactBuilder.InitializeFunc = func(injector di.Injector) error { return nil }
freshArtifactBuilder.AddFileFunc = func(path string, content []byte) error { return nil }
freshArtifactBuilder.AddFileFunc = func(path string, content []byte, mode os.FileMode) error { return nil }
freshArtifactBuilder.CreateFunc = func(outputPath string, tag string) (string, error) {
receivedOutputPath = outputPath
return "test-result.tar.gz", nil
Expand Down Expand Up @@ -386,7 +387,7 @@ func TestBundleCmd(t *testing.T) {
// Create a fresh artifact builder to avoid state contamination
freshArtifactBuilder := bundler.NewMockArtifact()
freshArtifactBuilder.InitializeFunc = func(injector di.Injector) error { return nil }
freshArtifactBuilder.AddFileFunc = func(path string, content []byte) error { return nil }
freshArtifactBuilder.AddFileFunc = func(path string, content []byte, mode os.FileMode) error { return nil }
freshArtifactBuilder.CreateFunc = func(outputPath string, tag string) (string, error) {
receivedTag = tag
return "test-result.tar.gz", nil
Expand Down
3 changes: 2 additions & 1 deletion cmd/push_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"os"
"testing"

"github.com/windsorcli/cli/pkg/bundler"
Expand Down Expand Up @@ -40,7 +41,7 @@ contexts:
// Create mock artifact builder
artifactBuilder := bundler.NewMockArtifact()
artifactBuilder.InitializeFunc = func(injector di.Injector) error { return nil }
artifactBuilder.AddFileFunc = func(path string, content []byte) error { return nil }
artifactBuilder.AddFileFunc = func(path string, content []byte, mode os.FileMode) error { return nil }
artifactBuilder.PushFunc = func(registryBase string, repoName string, tag string) error { return nil }

// Create mock template bundler
Expand Down
10 changes: 8 additions & 2 deletions pkg/blueprint/blueprint_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ func (b *BaseBlueprintHandler) processBlueprintTemplate(outputPath, content, con
// Private Methods
// =============================================================================

// resolveComponentSources processes each Terraform component's source field, expanding it into a full
// resolveComponentSources transforms component source names into fully qualified
// URL with path prefix and reference information based on the associated source configuration.
func (b *BaseBlueprintHandler) resolveComponentSources(blueprint *blueprintv1alpha1.Blueprint) {
resolvedComponents := make([]blueprintv1alpha1.TerraformComponent, len(blueprint.TerraformComponents))
Expand All @@ -694,6 +694,11 @@ func (b *BaseBlueprintHandler) resolveComponentSources(blueprint *blueprintv1alp
for i, component := range resolvedComponents {
for _, source := range blueprint.Sources {
if component.Source == source.Name {
// Skip URL resolution for OCI sources - let terraform generator handle them
if strings.HasPrefix(source.Url, "oci://") {
break
}

pathPrefix := source.PathPrefix
if pathPrefix == "" {
pathPrefix = "terraform"
Expand Down Expand Up @@ -731,7 +736,8 @@ func (b *BaseBlueprintHandler) resolveComponentPaths(blueprint *blueprintv1alpha
for i, component := range resolvedComponents {
componentCopy := component

if b.isValidTerraformRemoteSource(componentCopy.Source) {
// Check if this is a remote source (Git URL) or OCI source
if b.isValidTerraformRemoteSource(componentCopy.Source) || b.isOCISource(componentCopy.Source) {
componentCopy.FullPath = filepath.Join(projectRoot, ".windsor", ".tf_modules", componentCopy.Path)
} else {
componentCopy.FullPath = filepath.Join(projectRoot, "terraform", componentCopy.Path)
Expand Down
40 changes: 25 additions & 15 deletions pkg/bundler/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"archive/tar"
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"time"
Expand Down Expand Up @@ -73,7 +74,7 @@ type BlueprintMetadataInput struct {
// Artifact defines the interface for artifact creation operations
type Artifact interface {
Initialize(injector di.Injector) error
AddFile(path string, content []byte) error
AddFile(path string, content []byte, mode os.FileMode) error
Create(outputPath string, tag string) (string, error)
Push(registryBase string, repoName string, tag string) error
}
Expand All @@ -82,9 +83,15 @@ type Artifact interface {
// ArtifactBuilder Implementation
// =============================================================================

// FileInfo holds file content and permission information
type FileInfo struct {
Content []byte
Mode os.FileMode
}

// ArtifactBuilder implements the Artifact interface
type ArtifactBuilder struct {
files map[string][]byte
files map[string]FileInfo
shims *Shims
shell shell.Shell
tarballPath string
Expand All @@ -101,7 +108,7 @@ type ArtifactBuilder struct {
func NewArtifactBuilder() *ArtifactBuilder {
return &ArtifactBuilder{
shims: NewShims(),
files: make(map[string][]byte),
files: make(map[string]FileInfo),
}
}

Expand All @@ -128,8 +135,11 @@ func (a *ArtifactBuilder) Initialize(injector di.Injector) error {
// Files are held in memory until Create() or Push() is called. The path becomes the relative
// path within the generated tar.gz archive. Multiple calls with the same path will overwrite
// the previous content. Special handling exists for "_templates/metadata.yaml" during packaging.
func (a *ArtifactBuilder) AddFile(path string, content []byte) error {
a.files[path] = content
func (a *ArtifactBuilder) AddFile(path string, content []byte, mode os.FileMode) error {
a.files[path] = FileInfo{
Content: content,
Mode: mode,
}
return nil
}

Expand Down Expand Up @@ -278,11 +288,11 @@ func (a *ArtifactBuilder) parseTagAndResolveMetadata(repoName, tag string) (stri
}
}

metadataData, hasMetadata := a.files["_templates/metadata.yaml"]
metadataFileInfo, hasMetadata := a.files["_templates/metadata.yaml"]
var input BlueprintMetadataInput

if hasMetadata {
if err := a.shims.YamlUnmarshal(metadataData, &input); err != nil {
if err := a.shims.YamlUnmarshal(metadataFileInfo.Content, &input); err != nil {
return "", "", nil, fmt.Errorf("failed to parse metadata.yaml: %w", err)
}
}
Expand Down Expand Up @@ -349,22 +359,22 @@ func (a *ArtifactBuilder) createTarballInMemory(metadata []byte) ([]byte, error)
return nil, fmt.Errorf("failed to write metadata: %w", err)
}

for path, content := range a.files {
for path, fileInfo := range a.files {
if path == "_templates/metadata.yaml" {
continue
}

header := &tar.Header{
Name: path,
Mode: 0644,
Size: int64(len(content)),
Mode: int64(fileInfo.Mode),
Size: int64(len(fileInfo.Content)),
}

if err := tarWriter.WriteHeader(header); err != nil {
return nil, fmt.Errorf("failed to write header for %s: %w", path, err)
}

if _, err := tarWriter.Write(content); err != nil {
if _, err := tarWriter.Write(fileInfo.Content); err != nil {
return nil, fmt.Errorf("failed to write content for %s: %w", path, err)
}
}
Expand Down Expand Up @@ -412,22 +422,22 @@ func (a *ArtifactBuilder) createTarballToDisk(outputPath string, metadata []byte
return fmt.Errorf("failed to write metadata: %w", err)
}

for path, content := range a.files {
for path, fileInfo := range a.files {
if path == "_templates/metadata.yaml" {
continue
}

header := &tar.Header{
Name: path,
Mode: 0644,
Size: int64(len(content)),
Mode: int64(fileInfo.Mode),
Size: int64(len(fileInfo.Content)),
}

if err := tarWriter.WriteHeader(header); err != nil {
return fmt.Errorf("failed to write header for %s: %w", path, err)
}

if _, err := tarWriter.Write(content); err != nil {
if _, err := tarWriter.Write(fileInfo.Content); err != nil {
return fmt.Errorf("failed to write content for %s: %w", path, err)
}
}
Expand Down
Loading
Loading