Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interpolate COMPOSE_PROJECT_NAME with name from config file #272

Merged
merged 1 commit into from Jun 15, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions loader/full-example.yml
Expand Up @@ -25,6 +25,7 @@ services:
tags:
- foo:v1.0.0
- docker.io/username/foo:my-other-tag
- ${COMPOSE_PROJECT_NAME}:1.0.0


cap_add:
Expand Down
6 changes: 4 additions & 2 deletions loader/full-struct_test.go
Expand Up @@ -70,7 +70,7 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
Mode: uint32Ptr(0440),
},
},
Tags: []string{"foo:v1.0.0", "docker.io/username/foo:my-other-tag"},
Tags: []string{"foo:v1.0.0", "docker.io/username/foo:my-other-tag", "full_example_project_name:1.0.0"},
},
CapAdd: []string{"ALL"},
CapDrop: []string{"NET_ADMIN", "SYS_ADMIN"},
Expand Down Expand Up @@ -602,6 +602,7 @@ services:
tags:
- foo:v1.0.0
- docker.io/username/foo:my-other-tag
- full_example_project_name:1.0.0
cap_add:
- ALL
cap_drop:
Expand Down Expand Up @@ -1133,7 +1134,8 @@ func fullExampleJSON(workingDir, homeDir string) string {
],
"tags": [
"foo:v1.0.0",
"docker.io/username/foo:my-other-tag"
"docker.io/username/foo:my-other-tag",
"full_example_project_name:1.0.0"
]
},
"cap_add": [
Expand Down
35 changes: 26 additions & 9 deletions loader/loader.go
Expand Up @@ -160,6 +160,8 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
op(opts)
}

projectName := projectName(configDetails, opts)

var configs []*types.Config
for i, file := range configDetails.ConfigFiles {
configDict := file.Config
Expand Down Expand Up @@ -207,15 +209,6 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
s.EnvFile = newEnvFiles
}

projectName, projectNameImperativelySet := opts.GetProjectName()
model.Name = NormalizeProjectName(model.Name)
if !projectNameImperativelySet && model.Name != "" {
projectName = model.Name
}

if projectName != "" {
configDetails.Environment[consts.ComposeProjectName] = projectName
}
project := &types.Project{
Name: projectName,
WorkingDir: configDetails.WorkingDir,
Expand Down Expand Up @@ -245,6 +238,30 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
return project, nil
}

func projectName(details types.ConfigDetails, opts *Options) string {
projectName, projectNameImperativelySet := opts.GetProjectName()
var pjNameFromConfigFile string

for _, configFile := range details.ConfigFiles {
yml, err := ParseYAML(configFile.Content)
if err != nil {
return ""
}
if val, ok := yml["name"]; ok && val != "" {
pjNameFromConfigFile = yml["name"].(string)
}
}
pjNameFromConfigFile = NormalizeProjectName(pjNameFromConfigFile)
if !projectNameImperativelySet && pjNameFromConfigFile != "" {
projectName = pjNameFromConfigFile
}

if _, ok := details.Environment[consts.ComposeProjectName]; !ok && projectName != "" {
details.Environment[consts.ComposeProjectName] = projectName
}
return projectName
}

func NormalizeProjectName(s string) string {
r := regexp.MustCompile("[a-z0-9_-]")
s = strings.ToLower(s)
Expand Down
93 changes: 89 additions & 4 deletions loader/loader_test.go
Expand Up @@ -34,20 +34,32 @@ import (
)

func buildConfigDetails(yaml string, env map[string]string) types.ConfigDetails {
return buildConfigDetailsMultipleFiles(env, yaml)
}

func buildConfigDetailsMultipleFiles(env map[string]string, yamls ...string) types.ConfigDetails {
workingDir, err := os.Getwd()
if err != nil {
panic(err)
}

return types.ConfigDetails{
WorkingDir: workingDir,
ConfigFiles: []types.ConfigFile{
{Filename: "filename.yml", Content: []byte(yaml)},
},
WorkingDir: workingDir,
ConfigFiles: buildConfigFiles(yamls),
Environment: env,
}
}

func buildConfigFiles(yamls []string) []types.ConfigFile {
configFiles := []types.ConfigFile{}
for i, yaml := range yamls {
configFiles = append(configFiles, types.ConfigFile{
Filename: fmt.Sprintf("filename%d.yml", i),
Content: []byte(yaml)})
}
return configFiles
}

func loadYAML(yaml string) (*types.Project, error) {
return loadYAMLWithEnv(yaml, nil)
}
Expand Down Expand Up @@ -1951,3 +1963,76 @@ services:
assert.NilError(t, err)
assert.Equal(t, "value2", sshValue)
}

func TestProjectNameInterpolation(t *testing.T) {
t.Run("project name simple interpolation", func(t *testing.T) {
yaml := `
name: interpolated
services:
web:
image: web
container_name: ${COMPOSE_PROJECT_NAME}-web
`
configDetails := buildConfigDetails(yaml, map[string]string{})

actual, err := Load(configDetails)
assert.NilError(t, err)
svc, err := actual.GetService("web")
assert.NilError(t, err)
assert.Equal(t, "interpolated-web", svc.ContainerName)
})

t.Run("project name interpolation with override", func(t *testing.T) {
yaml1 := `
name: interpolated
services:
web:
image: web
container_name: ${COMPOSE_PROJECT_NAME}-web
`
yaml2 := `
name: overrided
services:
db:
image: db
container_name: ${COMPOSE_PROJECT_NAME}-db
`
yaml3 := `
services:
proxy:
image: proxy
container_name: ${COMPOSE_PROJECT_NAME}-proxy
`
configDetails := buildConfigDetailsMultipleFiles(map[string]string{}, yaml1, yaml2, yaml3)

actual, err := Load(configDetails)
assert.NilError(t, err)
svc, err := actual.GetService("web")
assert.NilError(t, err)
assert.Equal(t, "overrided-web", svc.ContainerName)

svc, err = actual.GetService("db")
assert.NilError(t, err)
assert.Equal(t, "overrided-db", svc.ContainerName)

svc, err = actual.GetService("proxy")
assert.NilError(t, err)
assert.Equal(t, "overrided-proxy", svc.ContainerName)
})

t.Run("project name env variable interpolation", func(t *testing.T) {
yaml := `
name: interpolated
services:
web:
image: web
container_name: ${COMPOSE_PROJECT_NAME}-web
`
configDetails := buildConfigDetails(yaml, map[string]string{"COMPOSE_PROJECT_NAME": "env-var"})
actual, err := Load(configDetails)
assert.NilError(t, err)
svc, err := actual.GetService("web")
assert.NilError(t, err)
assert.Equal(t, "env-var-web", svc.ContainerName)
})
}