Skip to content
Open
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
5 changes: 5 additions & 0 deletions playground/local_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,11 @@ func (d *LocalRunner) toDockerComposeService(s *Service) (map[string]interface{}
// create the bind volumes
var createdVolumes []string
for localPath, volume := range s.VolumesMapped {
if volume.HostPath != "" {
volumes[volume.HostPath] = localPath
continue
}

dockerVolumeName := d.createVolumeName(s.Name, volume.Name)

if volume.IsLocal {
Expand Down
15 changes: 13 additions & 2 deletions playground/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,9 @@ type Service struct {
}

type VolumeMapped struct {
Name string
IsLocal bool
Name string
IsLocal bool
HostPath string
}

type DependsOnCondition string
Expand Down Expand Up @@ -607,6 +608,16 @@ func (s *Service) WithVolume(name, localPath string, isLocalTri ...bool) *Servic
return s
}

func (s *Service) WithHostVolume(hostPath, containerPath string) *Service {
if s.VolumesMapped == nil {
s.VolumesMapped = make(map[string]*VolumeMapped)
}
s.VolumesMapped[containerPath] = &VolumeMapped{
HostPath: hostPath,
}
return s
}

func (s *Service) WithArtifact(localPath, artifactName string) *Service {
if s.FilesMapped == nil {
s.FilesMapped = make(map[string]string)
Expand Down
25 changes: 16 additions & 9 deletions playground/recipe_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ type YAMLServiceConfig struct {
}

type YAMLVolumeMappedConfig struct {
Name string `yaml:"name"`
IsLocal bool `yaml:"is_local"`
Name string `yaml:"name"`
IsLocal bool `yaml:"is_local"`
HostPath string `yaml:"host_path"`
}

// YAMLReleaseConfig specifies a GitHub release to download
Expand Down Expand Up @@ -481,9 +482,7 @@ func applyServiceOverrides(svc *Service, config *YAMLServiceConfig, root *Compon
applyFilesToService(svc, config.Files)
}
if config.Volumes != nil {
for containerPath, volumeMapping := range config.Volumes {
svc.WithVolume(volumeMapping.Name, containerPath, volumeMapping.IsLocal)
}
applyVolumesToService(svc, config.Volumes)
}
if config.DependsOn != nil {
applyDependsOn(svc, config.DependsOn, root)
Expand Down Expand Up @@ -573,7 +572,17 @@ func yamlReleaseToRelease(cfg *YAMLReleaseConfig) *release {
}
}

// applyFilesToService maps files to a service
// applyVolumesToService maps volumes to a service
func applyVolumesToService(svc *Service, volumes map[string]*YAMLVolumeMappedConfig) {
for containerPath, volumeMapping := range volumes {
if volumeMapping.HostPath != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No validation when a user sets conflicting fields (e.g. both host_path and name, or host_path + is_local: true). host_path silently wins. Consider validating mutual exclusivity here or documenting the precedence in the YAMLVolumeMappedConfig struct.

Also, unlike service-level HostPath which gets resolved via filepath.Abs, volume HostPath is passed through as-is. A relative path like ./data may resolve unexpectedly. Consider normalizing:

if volumeMapping.HostPath != "" {
    hostPath, err := filepath.Abs(volumeMapping.HostPath)
    // handle err
    svc.WithHostVolume(hostPath, containerPath)
}

svc.WithHostVolume(volumeMapping.HostPath, containerPath)
} else {
svc.WithVolume(volumeMapping.Name, containerPath, volumeMapping.IsLocal)
}
}
}

func applyFilesToService(svc *Service, files map[string]string) {
for containerPath, fileSource := range files {
var artifactName string
Expand Down Expand Up @@ -662,9 +671,7 @@ func createServiceFromConfig(name string, config *YAMLServiceConfig, root *Compo
applyFilesToService(svc, config.Files)
}
if config.Volumes != nil {
for containerPath, volumeMapping := range config.Volumes {
svc.WithVolume(volumeMapping.Name, containerPath, volumeMapping.IsLocal)
}
applyVolumesToService(svc, config.Volumes)
}
if config.DependsOn != nil {
applyDependsOn(svc, config.DependsOn, root)
Expand Down
16 changes: 16 additions & 0 deletions playground/recipe_yaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,22 @@ func TestCreateServiceFromConfig_WithVolumes(t *testing.T) {
require.Equal(t, "myvolume", svc.VolumesMapped["/data"].Name)
}

func TestCreateServiceFromConfig_WithHostPathVolume(t *testing.T) {
config := &YAMLServiceConfig{
Image: "test-image",
Volumes: map[string]*YAMLVolumeMappedConfig{"/var/run/docker.sock": {
HostPath: "/var/run/docker.sock",
}},
}

svc := createServiceFromConfig("my-service", config, nil, "")

require.NotNil(t, svc.VolumesMapped)
require.Equal(t, "/var/run/docker.sock", svc.VolumesMapped["/var/run/docker.sock"].HostPath)
require.Empty(t, svc.VolumesMapped["/var/run/docker.sock"].Name)
require.False(t, svc.VolumesMapped["/var/run/docker.sock"].IsLocal)
}

func TestParseYAMLRecipe(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "recipe-test")
require.NoError(t, err)
Expand Down
Loading