Skip to content

Commit 56e6c33

Browse files
authored
Merge pull request #294 from glours/use-dash-in-resource-names
use '-' as default separator and support of compatibility mode
2 parents 0ab97a2 + aa0ca5e commit 56e6c33

File tree

6 files changed

+95
-19
lines changed

6 files changed

+95
-19
lines changed

cli/options.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ func ProjectFromOptions(options *ProjectOptions) (*types.Project, error) {
350350

351351
options.loadOptions = append(options.loadOptions,
352352
withNamePrecedenceLoad(absWorkingDir, options),
353-
withConvertWindowsPaths(options))
353+
withConvertWindowsPaths(options),
354+
withSeparator(options))
354355

355356
project, err := loader.Load(types.ConfigDetails{
356357
ConfigFiles: configs,
@@ -384,6 +385,15 @@ func withConvertWindowsPaths(options *ProjectOptions) func(*loader.Options) {
384385
}
385386
}
386387

388+
// withSeparator defines loader.Options separator used to define resource names
389+
func withSeparator(options *ProjectOptions) func(*loader.Options) {
390+
return func(o *loader.Options) {
391+
if utils.StringToBool(options.Environment["COMPOSE_COMPATIBILITY"]) {
392+
o.Separator = loader.CompatibilitySeparator
393+
}
394+
}
395+
}
396+
387397
// getConfigPathsFromOptions retrieves the config files for project based on project options
388398
func getConfigPathsFromOptions(options *ProjectOptions) ([]string, error) {
389399
if len(options.ConfigPaths) != 0 {

cli/options_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,28 @@ func TestEnvMap(t *testing.T) {
237237
m = utils.GetAsEqualsMap(l)
238238
assert.Equal(t, m["foo"], "bar")
239239
}
240+
241+
func TestWithSeparator(t *testing.T) {
242+
t.Run("With default separator", func(t *testing.T) {
243+
opts, err := NewProjectOptions([]string{
244+
"testdata/simple/compose-with-network-and-volume.yaml",
245+
}, WithName("my-project"))
246+
assert.NilError(t, err)
247+
p, err := ProjectFromOptions(opts)
248+
assert.NilError(t, err)
249+
assert.Equal(t, p.Networks["test-network"].Name, "my-project-test-network")
250+
251+
})
252+
253+
t.Run("With compatibility separator", func(t *testing.T) {
254+
t.Setenv("COMPOSE_COMPATIBILITY", "true")
255+
opts, err := NewProjectOptions([]string{
256+
"testdata/simple/compose-with-network-and-volume.yaml",
257+
}, WithName("my-project"), WithOsEnv)
258+
assert.NilError(t, err)
259+
p, err := ProjectFromOptions(opts)
260+
assert.NilError(t, err)
261+
assert.Equal(t, p.Networks["test-network"].Name, "my-project_test-network")
262+
263+
})
264+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
services:
2+
simple:
3+
image: nginx
4+
networks:
5+
- test-network
6+
volumes:
7+
- test-volume
8+
networks:
9+
test-network:
10+
volumes:
11+
test-volume:

loader/loader.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ import (
4343
"gopkg.in/yaml.v2"
4444
)
4545

46+
const (
47+
DefaultSeparator = "-"
48+
CompatibilitySeparator = "_"
49+
)
50+
4651
// Options supported by Load
4752
type Options struct {
4853
// Skip schema validation
@@ -67,6 +72,8 @@ type Options struct {
6772
projectName string
6873
// Indicates when the projectName was imperatively set or guessed from path
6974
projectNameImperativelySet bool
75+
// Set separator used for naming resources
76+
Separator string
7077
}
7178

7279
func (o *Options) SetProjectName(name string, imperativelySet bool) {
@@ -155,6 +162,7 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
155162
LookupValue: configDetails.LookupEnv,
156163
TypeCastMapping: interpolateTypeCastMapping,
157164
},
165+
Separator: DefaultSeparator,
158166
}
159167

160168
for _, op := range options {
@@ -223,7 +231,7 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
223231
}
224232

225233
if !opts.SkipNormalization {
226-
err = normalize(project, opts.ResolvePaths)
234+
err = normalize(project, opts.ResolvePaths, opts.Separator)
227235
if err != nil {
228236
return nil, err
229237
}

loader/normalize.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
)
2929

3030
// normalize compose project by moving deprecated attributes to their canonical position and injecting implicit defaults
31-
func normalize(project *types.Project, resolvePaths bool) error {
31+
func normalize(project *types.Project, resolvePaths bool, separator string) error {
3232
absWorkingDir, err := filepath.Abs(project.WorkingDir)
3333
if err != nil {
3434
return err
@@ -110,7 +110,7 @@ func normalize(project *types.Project, resolvePaths bool) error {
110110
project.Services[i] = s
111111
}
112112

113-
setNameFromKey(project)
113+
setNameFromKey(project, separator)
114114

115115
return nil
116116
}
@@ -143,31 +143,31 @@ func absComposeFiles(composeFiles []string) ([]string, error) {
143143
}
144144

145145
// Resources with no explicit name are actually named by their key in map
146-
func setNameFromKey(project *types.Project) {
146+
func setNameFromKey(project *types.Project, separator string) {
147147
for i, n := range project.Networks {
148148
if n.Name == "" {
149-
n.Name = fmt.Sprintf("%s_%s", project.Name, i)
149+
n.Name = fmt.Sprintf("%s%s%s", project.Name, separator, i)
150150
project.Networks[i] = n
151151
}
152152
}
153153

154154
for i, v := range project.Volumes {
155155
if v.Name == "" {
156-
v.Name = fmt.Sprintf("%s_%s", project.Name, i)
156+
v.Name = fmt.Sprintf("%s%s%s", project.Name, separator, i)
157157
project.Volumes[i] = v
158158
}
159159
}
160160

161161
for i, c := range project.Configs {
162162
if c.Name == "" {
163-
c.Name = fmt.Sprintf("%s_%s", project.Name, i)
163+
c.Name = fmt.Sprintf("%s%s%s", project.Name, separator, i)
164164
project.Configs[i] = c
165165
}
166166
}
167167

168168
for i, s := range project.Secrets {
169169
if s.Name == "" {
170-
s.Name = fmt.Sprintf("%s_%s", project.Name, i)
170+
s.Name = fmt.Sprintf("%s%s%s", project.Name, separator, i)
171171
project.Secrets[i] = s
172172
}
173173
}

loader/normalize_test.go

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,16 @@ services:
7373
default: null
7474
networks:
7575
default:
76-
name: myProject_default
76+
name: myProject-default
7777
myExternalnet:
7878
name: myExternalnet
7979
external: true
8080
myNamedNet:
8181
name: CustomName
8282
mynet:
83-
name: myProject_mynet
83+
name: myProject-mynet
8484
`
85-
err := normalize(&project, false)
85+
err := normalize(&project, false, DefaultSeparator)
8686
assert.NilError(t, err)
8787
marshal, err := yaml.Marshal(project)
8888
assert.NilError(t, err)
@@ -116,9 +116,9 @@ services:
116116
default: null
117117
networks:
118118
default:
119-
name: myProject_default
119+
name: myProject-default
120120
`, filepath.Join(wd, "testdata"))
121-
err := normalize(&project, true)
121+
err := normalize(&project, true, DefaultSeparator)
122122
assert.NilError(t, err)
123123
marshal, err := yaml.Marshal(project)
124124
assert.NilError(t, err)
@@ -138,11 +138,11 @@ func TestNormalizeAbsolutePaths(t *testing.T) {
138138

139139
expected := types.Project{
140140
Name: "myProject",
141-
Networks: types.Networks{"default": {Name: "myProject_default"}},
141+
Networks: types.Networks{"default": {Name: "myProject-default"}},
142142
WorkingDir: absWorkingDir,
143143
ComposeFiles: []string{absComposeFile, absOverrideFile},
144144
}
145-
err := normalize(&project, false)
145+
err := normalize(&project, false, DefaultSeparator)
146146
assert.NilError(t, err)
147147
assert.DeepEqual(t, expected, project)
148148
}
@@ -166,21 +166,43 @@ func TestNormalizeVolumes(t *testing.T) {
166166
absCwd, _ := filepath.Abs(".")
167167
expected := types.Project{
168168
Name: "myProject",
169-
Networks: types.Networks{"default": {Name: "myProject_default"}},
169+
Networks: types.Networks{"default": {Name: "myProject-default"}},
170170
Volumes: types.Volumes{
171171
"myExternalVol": {
172172
Name: "myExternalVol",
173173
External: types.External{External: true},
174174
},
175-
"myvol": {Name: "myProject_myvol"},
175+
"myvol": {Name: "myProject-myvol"},
176176
"myNamedVol": {
177177
Name: "CustomName",
178178
},
179179
},
180180
WorkingDir: absCwd,
181181
ComposeFiles: []string{},
182182
}
183-
err := normalize(&project, false)
183+
err := normalize(&project, false, DefaultSeparator)
184+
assert.NilError(t, err)
185+
assert.DeepEqual(t, expected, project)
186+
}
187+
188+
func TestNormalizeWithCompatibilitySeparator(t *testing.T) {
189+
project := types.Project{
190+
Name: "myProject",
191+
WorkingDir: "testdata",
192+
Networks: types.Networks{},
193+
ComposeFiles: []string{filepath.Join("testdata", "simple", "compose.yaml"), filepath.Join("testdata", "simple", "compose-with-overrides.yaml")},
194+
}
195+
absWorkingDir, _ := filepath.Abs("testdata")
196+
absComposeFile, _ := filepath.Abs(filepath.Join("testdata", "simple", "compose.yaml"))
197+
absOverrideFile, _ := filepath.Abs(filepath.Join("testdata", "simple", "compose-with-overrides.yaml"))
198+
199+
expected := types.Project{
200+
Name: "myProject",
201+
Networks: types.Networks{"default": {Name: "myProject_default"}},
202+
WorkingDir: absWorkingDir,
203+
ComposeFiles: []string{absComposeFile, absOverrideFile},
204+
}
205+
err := normalize(&project, false, "_")
184206
assert.NilError(t, err)
185207
assert.DeepEqual(t, expected, project)
186208
}

0 commit comments

Comments
 (0)