Skip to content

Commit 56297d8

Browse files
idsulikndeloof
authored andcommitted
feat: Add label_file support to service
Signed-off-by: Suleiman Dibirov <[email protected]>
1 parent df253f2 commit 56297d8

File tree

13 files changed

+277
-4
lines changed

13 files changed

+277
-4
lines changed

loader/loader.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,8 @@ func modelToProject(dict map[string]interface{}, opts *Options, configDetails ty
637637
return nil, err
638638
}
639639
}
640+
641+
project, err = project.WithServicesLabelsResolved(opts.discardEnvFiles)
640642
return project, nil
641643
}
642644

loader/loader_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,6 +2319,31 @@ func TestLoadServiceWithEnvFile(t *testing.T) {
23192319
assert.Equal(t, "YES", *service.Environment["HALLO"])
23202320
}
23212321

2322+
func TestLoadServiceWithLabelFile(t *testing.T) {
2323+
file, err := os.CreateTemp("", "test-compose-go")
2324+
assert.NilError(t, err)
2325+
defer os.Remove(file.Name())
2326+
2327+
_, err = file.Write([]byte("MY_LABEL=MY_VALUE"))
2328+
assert.NilError(t, err)
2329+
2330+
p := &types.Project{
2331+
Services: types.Services{
2332+
"test": {
2333+
Name: "test",
2334+
LabelFiles: []types.LabelFile{
2335+
{Path: file.Name(), Required: true},
2336+
},
2337+
},
2338+
},
2339+
}
2340+
p, err = p.WithServicesLabelsResolved(false)
2341+
assert.NilError(t, err)
2342+
service, err := p.GetService("test")
2343+
assert.NilError(t, err)
2344+
assert.Equal(t, "MY_VALUE", service.Labels["MY_LABEL"])
2345+
}
2346+
23222347
func TestLoadNoSSHInBuildConfig(t *testing.T) {
23232348
actual, err := loadYAML(`
23242349
name: load-no-ssh-in-build-config

override/merge.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ func init() {
5757
mergeSpecials["services.*.dns_search"] = mergeToSequence
5858
mergeSpecials["services.*.entrypoint"] = override
5959
mergeSpecials["services.*.env_file"] = mergeToSequence
60+
mergeSpecials["services.*.label_file"] = mergeToSequence
6061
mergeSpecials["services.*.environment"] = mergeToSequence
6162
mergeSpecials["services.*.extra_hosts"] = mergeExtraHosts
6263
mergeSpecials["services.*.healthcheck.test"] = override

override/uncity.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func init() {
5151
unique["services.*.env_file"] = envFileIndexer
5252
unique["services.*.expose"] = exposeIndexer
5353
unique["services.*.labels"] = keyValueIndexer
54+
unique["services.*.label_file"] = labelFileIndexer
5455
unique["services.*.links"] = keyValueIndexer
5556
unique["services.*.networks.*.aliases"] = keyValueIndexer
5657
unique["services.*.networks.*.link_local_ips"] = keyValueIndexer
@@ -227,3 +228,16 @@ func envFileIndexer(y any, p tree.Path) (string, error) {
227228
}
228229
return "", nil
229230
}
231+
232+
func labelFileIndexer(y any, p tree.Path) (string, error) {
233+
switch value := y.(type) {
234+
case string:
235+
return value, nil
236+
case map[string]any:
237+
if pathValue, ok := value["path"]; ok {
238+
return pathValue.(string), nil
239+
}
240+
return "", fmt.Errorf("label path attribute %s is missing", p)
241+
}
242+
return "", nil
243+
}

paths/resolve.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func ResolveRelativePaths(project map[string]any, base string, remotes []RemoteR
3737
"services.*.build.context": r.absContextPath,
3838
"services.*.build.additional_contexts.*": r.absContextPath,
3939
"services.*.env_file.*.path": r.absPath,
40+
"services.*.label_file.*.path": r.absPath,
4041
"services.*.extends.file": r.absExtendsPath,
4142
"services.*.develop.watch.*.path": r.absSymbolicLink,
4243
"services.*.volumes.*": r.absVolumeMount,

schema/compose-spec.json

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@
240240
"domainname": {"type": "string"},
241241
"entrypoint": {"$ref": "#/definitions/command"},
242242
"env_file": {"$ref": "#/definitions/env_file"},
243+
"label_file": {"$ref": "#/definitions/label_file"},
243244
"environment": {"$ref": "#/definitions/list_or_dict"},
244245

245246
"expose": {
@@ -866,7 +867,34 @@
866867
"path": {
867868
"type": "string"
868869
},
869-
"format": {
870+
"required": {
871+
"type": ["boolean", "string"],
872+
"default": true
873+
}
874+
},
875+
"required": [
876+
"path"
877+
]
878+
}
879+
]
880+
}
881+
}
882+
]
883+
},
884+
885+
"label_file": {
886+
"oneOf": [
887+
{"type": "string"},
888+
{
889+
"type": "array",
890+
"items": {
891+
"oneOf": [
892+
{"type": "string"},
893+
{
894+
"type": "object",
895+
"additionalProperties": false,
896+
"properties": {
897+
"path": {
870898
"type": "string"
871899
},
872900
"required": {

transform/canonical.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func init() {
3030
transformers["services.*.build.additional_contexts"] = transformKeyValue
3131
transformers["services.*.depends_on"] = transformDependsOn
3232
transformers["services.*.env_file"] = transformEnvFile
33+
transformers["services.*.label_file"] = transformLabelFile
3334
transformers["services.*.extends"] = transformExtends
3435
transformers["services.*.networks"] = transformServiceNetworks
3536
transformers["services.*.volumes.*"] = transformVolumeMount

transform/labelfile.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
Copyright 2020 The Compose Specification Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package transform
18+
19+
import (
20+
"fmt"
21+
22+
"github.com/compose-spec/compose-go/v2/tree"
23+
)
24+
25+
func transformLabelFile(data any, p tree.Path, _ bool) (any, error) {
26+
switch v := data.(type) {
27+
case string:
28+
return []any{
29+
transformLabelFileValue(v),
30+
}, nil
31+
case []any:
32+
for i, e := range v {
33+
v[i] = transformLabelFileValue(e)
34+
}
35+
return v, nil
36+
default:
37+
return nil, fmt.Errorf("%s: invalid type %T for label_file", p, v)
38+
}
39+
}
40+
41+
func transformLabelFileValue(data any) any {
42+
switch v := data.(type) {
43+
case string:
44+
return map[string]any{
45+
"path": v,
46+
"required": true,
47+
}
48+
case map[string]any:
49+
if _, ok := v["required"]; !ok {
50+
v["required"] = true
51+
}
52+
return v
53+
}
54+
return nil
55+
}

types/derived.gen.go

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

types/labelfile.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright 2020 The Compose Specification Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package types
18+
19+
import (
20+
"encoding/json"
21+
)
22+
23+
type LabelFile struct {
24+
Path string `yaml:"path,omitempty" json:"path,omitempty"`
25+
Required bool `yaml:"required" json:"required"`
26+
Format string `yaml:"format,omitempty" json:"format,omitempty"`
27+
}
28+
29+
// MarshalYAML makes LabelFile implement yaml.Marshaler
30+
func (e LabelFile) MarshalYAML() (interface{}, error) {
31+
if e.Required {
32+
return e.Path, nil
33+
}
34+
return map[string]any{
35+
"path": e.Path,
36+
"required": e.Required,
37+
}, nil
38+
}
39+
40+
// MarshalJSON makes LabelFile implement json.Marshaler
41+
func (e *LabelFile) MarshalJSON() ([]byte, error) {
42+
if e.Required {
43+
return json.Marshal(e.Path)
44+
}
45+
// Pass as a value to avoid re-entering this method and use the default implementation
46+
return json.Marshal(*e)
47+
}

0 commit comments

Comments
 (0)