Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
23 changes: 15 additions & 8 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 @@ -574,6 +573,16 @@ func yamlReleaseToRelease(cfg *YAMLReleaseConfig) *release {
}

// applyFilesToService maps files 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