nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: dgraph-io/badger
Pull request #1609 (2020-12-03 03:27:36)

Fix(OOM): Reuse pb.KVs in Stream
We store a slice of pb.KVs in Iterator, so it can be used by Stream users.

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/dgraph-io/badger/1609)
<!-- Reviewable:end -->



Patch:
diff --git a/backup.go b/backup.go
index c729a38..ee3d6d7 100644
--- a/backup.go
+++ b/backup.go
@@ -87,7 +87,8 @@ func (stream *Stream) Backup(w io.Writer, since uint64) (uint64, error) {
 
 			// clear txn bits
 			meta := item.meta &^ (bitTxn | bitFinTxn)
-			kv := &pb.KV{
+			kv := itr.NewKV()
+			*kv = pb.KV{
 				Key:       item.KeyCopy(nil),
 				Value:     valCopy,
 				UserMeta:  []byte{item.UserMeta()},
diff --git a/iterator.go b/iterator.go
index 8f086c6..f176fa3 100644
--- a/iterator.go
+++ b/iterator.go
@@ -26,6 +26,7 @@ import (
 	"sync/atomic"
 	"time"
 
+	"github.com/dgraph-io/badger/v2/pb"
 	"github.com/dgraph-io/badger/v2/table"
 
 	"github.com/dgraph-io/badger/v2/y"
@@ -421,6 +422,8 @@ type Iterator struct {
 	// the iterator. It can be used, for example, to uniquely identify each of the
 	// iterators created by the stream interface
 	ThreadId int
+
+	reuse []*pb.KV
 }
 
 // NewIterator returns a new iterator. Depending upon the options, either only keys, or both
@@ -480,6 +483,20 @@ func (txn *Txn) NewKeyIterator(key []byte, opt IteratorOptions) *Iterator {
 	return txn.NewIterator(opt)
 }
 
+// NewKV must be called serially. It is NOT thread-safe.
+func (it *Iterator) NewKV() *pb.KV {
+	if len(it.reuse) == 0 {
+		return &pb.KV{}
+	}
+	kv := it.reuse[len(it.reuse)-1]
+	it.reuse = it.reuse[:len(it.reuse)-1]
+	if kv == nil {
+		kv = &pb.KV{}
+	}
+	kv.Reset()
+	return kv
+}
+
 func (it *Iterator) newItem() *Item {
 	item := it.waste.pop()
 	if item == nil {
diff --git a/stream.go b/stream.go
index 2bb5337..8733fe1 100644
--- a/stream.go
+++ b/stream.go
@@ -110,7 +110,7 @@ func (st *Stream) ToList(key []byte, itr *Iterator) (*pb.KVList, error) {
 			break
 		}
 
-		kv := &pb.KV{}
+		kv := itr.NewKV()
 		kv.Key = ka
 
 		if err := item.Value(func(val []byte) error {
@@ -245,6 +245,9 @@ func (st *Stream) produceKVs(ctx context.Context, threadId int) error {
 					return err
 				}
 			}
+			if len(itr.reuse) < 100 {
+				itr.reuse = append(itr.reuse, list.Kv...)
+			}
 		}
 		// Mark the stream as done.
 		if st.doneMarkers {


Test patch:
diff --git a/stream_test.go b/stream_test.go
index 35787c7..1bc7b97 100644
--- a/stream_test.go
+++ b/stream_test.go
@@ -300,7 +300,8 @@ func TestStreamCustomKeyToList(t *testing.T) {
 		if err != nil {
 			return nil, err
 		}
-		kv := &pb.KV{
+		kv := itr.NewKV()
+		*kv = pb.KV{
 			Key:   y.Copy(item.Key()),
 			Value: val,
 		}
Repository: GoogleCloudPlatform/opentelemetry-operations-go
Pull request #379 (2022-05-03 19:27:03)

Add struct tag for sum of squared deviations estimate and factory test.
This should fix failures in https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/9679, and adds a test to make sure we don't hit them again.


Patch:
diff --git a/exporter/collector/config.go b/exporter/collector/config.go
index 1a60842..7ce73cc 100644
--- a/exporter/collector/config.go
+++ b/exporter/collector/config.go
@@ -105,7 +105,7 @@ type MetricConfig struct {
 	// This enables calculation of an estimated sum of squared deviation.  It isn't correct,
 	// so we don't send it by default, and don't expose it to users. For some uses, it is
 	// expected, however.
-	EnableSumOfSquaredDeviation bool
+	EnableSumOfSquaredDeviation bool `mapstructure:"sum_of_squared_deviation"`
 }
 
 type ResourceFilter struct {


Test patch:
diff --git a/exporter/collector/integrationtest/factory_test.go b/exporter/collector/integrationtest/factory_test.go
new file mode 100644
index 0000000..3c77c47
--- /dev/null
+++ b/exporter/collector/integrationtest/factory_test.go
@@ -0,0 +1,30 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package integrationtest
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"go.opentelemetry.io/collector/config/configtest"
+
+	"github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/collector"
+)
+
+func TestCreateDefaultConfig(t *testing.T) {
+	cfg := collector.DefaultConfig()
+	assert.NotNil(t, cfg, "failed to create default config")
+	assert.NoError(t, configtest.CheckConfigStruct(cfg))
+}
Repository: GoogleCloudPlatform/opentelemetry-operations-go
Pull request #444 (2022-06-23 20:25:38)

Added TraceSampled Attribute
To get the trace details working in gcp logs console traceSampled is required in the logs. So we have added the trace_sampled attribute in the way similar to log_name to get trace details working.

google-cla[bot]: Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this [failed invocation](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/pull/444/checks?check_run_id=7031314000) of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.
damemi: /gcbrun
davidgargti20: @damemi can you please review it again and approve this
damemi: CI reporting bug is known, manually merging

Patch:
diff --git a/exporter/collector/logs.go b/exporter/collector/logs.go
index 035759e..c41fd25 100644
--- a/exporter/collector/logs.go
+++ b/exporter/collector/logs.go
@@ -45,6 +45,7 @@ const (
 	HTTPRequestAttributeKey    = "gcp.http_request"
 	LogNameAttributeKey        = "gcp.log_name"
 	SourceLocationAttributeKey = "gcp.source_location"
+	TraceSampledAttributeKey   = "gcp.trace_sampled"
 )
 
 // severityMapping maps the integer severity level values from OTel [0-24]
@@ -321,6 +322,12 @@ func (l logMapper) logToSplitEntries(
 		delete(attrsMap, SourceLocationAttributeKey)
 	}
 
+	// parse TraceSampled boolean from OTel attribute
+	if traceSampled, ok := attrsMap[TraceSampledAttributeKey]; ok {
+		entry.TraceSampled = traceSampled.BoolVal()
+		delete(attrsMap, TraceSampledAttributeKey)
+	}
+
 	// parse TraceID and SpanID, if present
 	if !log.TraceID().IsEmpty() {
 		entry.Trace = fmt.Sprintf("projects/%s/traces/%s", projectID, log.TraceID().HexString())


Test patch:
diff --git a/exporter/collector/logs_test.go b/exporter/collector/logs_test.go
index b11b2a3..3fe9ec4 100644
--- a/exporter/collector/logs_test.go
+++ b/exporter/collector/logs_test.go
@@ -218,6 +218,27 @@ func TestLogMapping(t *testing.T) {
 			},
 			maxEntrySize: defaultMaxEntrySize,
 		},
+		{
+			name: "log with traceSampled (bool)",
+			mr: func() *monitoredres.MonitoredResource {
+				return nil
+			},
+			log: func() plog.LogRecord {
+				log := plog.NewLogRecord()
+				log.Attributes().Insert(
+					TraceSampledAttributeKey,
+					pcommon.NewValueBool(true),
+				)
+				return log
+			},
+			expectedEntries: []logging.Entry{
+				{
+					TraceSampled: true,
+					Timestamp:    testObservedTime,
+				},
+			},
+			maxEntrySize: defaultMaxEntrySize,
+		},
 		{
 			name: "log with trace and span id",
 			mr: func() *monitoredres.MonitoredResource {
Repository: compose-spec/compose-go
Pull request #282 (2022-07-06 06:16:46)

Add support of platforms in the build section
Depends on:
- compose-spec/compose-spec#267



Patch:
diff --git a/loader/full-example.yml b/loader/full-example.yml
index 2687b05..cb300c9 100644
--- a/loader/full-example.yml
+++ b/loader/full-example.yml
@@ -26,6 +26,9 @@ services:
         - foo:v1.0.0
         - docker.io/username/foo:my-other-tag
         - ${COMPOSE_PROJECT_NAME}:1.0.0
+      platforms:
+        - linux/amd64
+        - linux/arm64
 
 
     cap_add:
diff --git a/schema/compose-spec.json b/schema/compose-spec.json
index 2500ce7..d444e71 100644
--- a/schema/compose-spec.json
+++ b/schema/compose-spec.json
@@ -103,7 +103,8 @@
                 "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
                 "isolation": {"type": "string"},
                 "secrets": {"$ref": "#/definitions/service_config_or_secret"},
-                "tags": {"type": "array", "items": {"type": "string"}}
+                "tags": {"type": "array", "items": {"type": "string"}},
+                "platforms": {"type": "array", "items": {"type": "string"}}
               },
               "additionalProperties": false,
               "patternProperties": {"^x-": {}}
diff --git a/types/types.go b/types/types.go
index b54679e..3c4369a 100644
--- a/types/types.go
+++ b/types/types.go
@@ -306,6 +306,7 @@ type BuildConfig struct {
 	Target     string                `yaml:",omitempty" json:"target,omitempty"`
 	Secrets    []ServiceSecretConfig `yaml:",omitempty" json:"secrets,omitempty"`
 	Tags       StringList            `mapstructure:"tags" yaml:"tags,omitempty" json:"tags,omitempty"`
+	Platforms  StringList            `mapstructure:"platforms" yaml:"platforms,omitempty" json:"platforms,omitempty"`
 
 	Extensions map[string]interface{} `yaml:",inline" json:"-"`
 }


Test patch:
diff --git a/loader/full-struct_test.go b/loader/full-struct_test.go
index 42f8c03..4914c5b 100644
--- a/loader/full-struct_test.go
+++ b/loader/full-struct_test.go
@@ -70,7 +70,8 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
 						Mode:   uint32Ptr(0440),
 					},
 				},
-				Tags: []string{"foo:v1.0.0", "docker.io/username/foo:my-other-tag", "full_example_project_name:1.0.0"},
+				Tags:      []string{"foo:v1.0.0", "docker.io/username/foo:my-other-tag", "full_example_project_name:1.0.0"},
+				Platforms: []string{"linux/amd64", "linux/arm64"},
 			},
 			CapAdd:       []string{"ALL"},
 			CapDrop:      []string{"NET_ADMIN", "SYS_ADMIN"},
@@ -605,6 +606,9 @@ services:
       - foo:v1.0.0
       - docker.io/username/foo:my-other-tag
       - full_example_project_name:1.0.0
+      platforms:
+      - linux/amd64
+      - linux/arm64
     cap_add:
     - ALL
     cap_drop:
@@ -1140,6 +1144,10 @@ func fullExampleJSON(workingDir, homeDir string) string {
           "foo:v1.0.0",
           "docker.io/username/foo:my-other-tag",
           "full_example_project_name:1.0.0"
+        ],
+        "platforms": [
+          "linux/amd64",
+          "linux/arm64"
         ]
       },
       "cap_add": [
Repository: compose-spec/compose-go
Pull request #283 (2022-07-12 20:42:40)

Fix hash usage in environment values
Resolves https://github.com/docker/compose/issues/9509


Patch:
diff --git a/dotenv/godotenv.go b/dotenv/godotenv.go
index 98d6620..6685dff 100644
--- a/dotenv/godotenv.go
+++ b/dotenv/godotenv.go
@@ -242,18 +242,16 @@ func parseLineWithLookup(line string, envMap map[string]string, lookupFn LookupF
 	}
 
 	// ditch the comments (but keep quoted hashes)
-	if strings.Contains(line, "#") {
+	if strings.HasPrefix(strings.TrimSpace(line), "#") || strings.Contains(line, " #") {
 		segmentsBetweenHashes := strings.Split(line, "#")
 		quotesAreOpen := false
 		var segmentsToKeep []string
 		for _, segment := range segmentsBetweenHashes {
 			if strings.Count(segment, "\"") == 1 || strings.Count(segment, "'") == 1 {
 				if quotesAreOpen {
-					quotesAreOpen = false
 					segmentsToKeep = append(segmentsToKeep, segment)
-				} else {
-					quotesAreOpen = true
 				}
+				quotesAreOpen = !quotesAreOpen
 			}
 
 			if len(segmentsToKeep) == 0 || quotesAreOpen {


Test patch:
diff --git a/dotenv/godotenv_test.go b/dotenv/godotenv_test.go
index 1bc726f..e0dde43 100644
--- a/dotenv/godotenv_test.go
+++ b/dotenv/godotenv_test.go
@@ -386,6 +386,7 @@ func TestParsing(t *testing.T) {
 	// it 'ignores inline comments' do
 	// expect(env("foo=bar # this is foo")).to eql('foo' => 'bar')
 	parseAndCompare(t, "FOO=bar # this is foo", "FOO", "bar")
+	parseAndCompare(t, "FOO=123#not-an-inline-comment", "FOO", "123#not-an-inline-comment")
 
 	// it 'allows # in quoted value' do
 	// expect(env('foo="bar#baz" # comment')).to eql('foo' => 'bar#baz')
Repository: compose-spec/compose-go
Pull request #307 (2022-09-23 15:34:53)

env: fix errors on valid interpolation expressions
The parser was too strict here and would reject valid constructs that used an unescaped `$` that was not part of a variable expression (and not ambiguous).

Now, only errors for unmatched braced expressions (e.g. `${FOO`) are returned, but other valid cases are ignored and the `$` will be treated literally, e.g. `a $ string` -> `a $ string`, which is the same as in POSIX.

glours: @milas can you sign-off your commit please 😂 ?

Patch:
diff --git a/template/template.go b/template/template.go
index 7056a13..27f7067 100644
--- a/template/template.go
+++ b/template/template.go
@@ -31,7 +31,7 @@ var substitutionNamed = "[_a-z][_a-z0-9]*"
 var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-+?](.*}|[^}]*))?"
 
 var patternString = fmt.Sprintf(
-	"%s(?i:(?P<escaped>%s)|(?P<named>%s)|{(?P<braced>%s)}|(?P<invalid>))",
+	"%s(?i:(?P<escaped>%s)|(?P<named>%s)|{(?:(?P<braced>%s)}|(?P<invalid>)))",
 	delimiter, delimiter, substitutionNamed, substitutionBraced,
 )
 


Test patch:
diff --git a/template/template_test.go b/template/template_test.go
index a2a0444..27c0f0e 100644
--- a/template/template_test.go
+++ b/template/template_test.go
@@ -47,10 +47,24 @@ func TestSubstituteNoMatch(t *testing.T) {
 	assert.Equal(t, "foo", result)
 }
 
+func TestUnescaped(t *testing.T) {
+	templates := []string{
+		"a $ string",
+		"^REGEX$",
+		"$}",
+		"$",
+	}
+
+	for _, expected := range templates {
+		actual, err := Substitute(expected, defaultMapping)
+		assert.NilError(t, err)
+		assert.Equal(t, expected, actual)
+	}
+}
+
 func TestInvalid(t *testing.T) {
 	invalidTemplates := []string{
 		"${",
-		"$}",
 		"${}",
 		"${ }",
 		"${ foo}",
Repository: compose-spec/compose-go
Pull request #324 (2022-11-30 15:34:29)

support merging boolean pointers
Test case and workaround, awaiting a fix for https://github.com/imdario/mergo/issues/131
see https://github.com/docker/compose/issues/9943


Patch:
diff --git a/loader/merge.go b/loader/merge.go
index ce7c1dc..019ebac 100644
--- a/loader/merge.go
+++ b/loader/merge.go
@@ -43,6 +43,15 @@ var serviceSpecials = &specials{
 }
 
 func (s *specials) Transformer(t reflect.Type) func(dst, src reflect.Value) error {
+	// TODO this is a workaround waiting for imdario/mergo#131
+	if t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Bool {
+		return func(dst, src reflect.Value) error {
+			if dst.CanSet() && !src.IsNil() {
+				dst.Set(src)
+			}
+			return nil
+		}
+	}
 	if fn, ok := s.m[t]; ok {
 		return fn
 	}
@@ -113,7 +122,10 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
 }
 
 func _merge(baseService *types.ServiceConfig, overrideService *types.ServiceConfig) (*types.ServiceConfig, error) {
-	if err := mergo.Merge(baseService, overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(serviceSpecials)); err != nil {
+	if err := mergo.Merge(baseService, overrideService,
+		mergo.WithAppendSlice,
+		mergo.WithOverride,
+		mergo.WithTransformers(serviceSpecials)); err != nil {
 		return nil, err
 	}
 	if overrideService.Command != nil {


Test patch:
diff --git a/loader/merge_test.go b/loader/merge_test.go
index 4f173b1..bbe32cd 100644
--- a/loader/merge_test.go
+++ b/loader/merge_test.go
@@ -1110,6 +1110,45 @@ func TestMergeUlimitsConfig(t *testing.T) {
 	)
 }
 
+func TestInitOverride(t *testing.T) {
+	var (
+		bt = true
+		bf = false
+	)
+	cases := []struct {
+		base     *bool
+		override *bool
+		expect   bool
+	}{
+		{
+			base:     &bt,
+			override: &bf,
+			expect:   false,
+		},
+		{
+			base:     nil,
+			override: &bt,
+			expect:   true,
+		},
+		{
+			base:     &bt,
+			override: nil,
+			expect:   true,
+		},
+	}
+	for _, test := range cases {
+		base := types.ServiceConfig{
+			Init: test.base,
+		}
+		override := types.ServiceConfig{
+			Init: test.override,
+		}
+		config, err := _merge(&base, &override)
+		assert.NilError(t, err)
+		assert.Check(t, *config.Init == test.expect)
+	}
+}
+
 func TestMergeServiceNetworkConfig(t *testing.T) {
 	specials := &specials{
 		m: map[reflect.Type]func(dst, src reflect.Value) error{
Repository: compose-spec/compose-go
Pull request #326 (2022-12-06 12:09:07)

prefer list format for extra_hosts to preserve backward compatibility
While map format is supported by Docker Compose v1, and proposed to be officially documented (https://github.com/compose-spec/compose-spec/pull/285), still most users rely on the list format and we should prefer this one to enforce backward compatibility.

close https://github.com/docker/compose/issues/10038


Patch:
diff --git a/loader/full-example.yml b/loader/full-example.yml
index 2ae6c48..585c31b 100644
--- a/loader/full-example.yml
+++ b/loader/full-example.yml
@@ -160,8 +160,8 @@ services:
     #   somehost: "162.242.195.82"
     #   otherhost: "50.31.209.229"
     extra_hosts:
-      - "somehost:162.242.195.82"
       - "otherhost:50.31.209.229"
+      - "somehost:162.242.195.82"
 
     hostname: foo
 
diff --git a/types/types.go b/types/types.go
index b01167b..2c4f02d 100644
--- a/types/types.go
+++ b/types/types.go
@@ -539,6 +539,18 @@ func (h HostsList) AsList() []string {
 	return l
 }
 
+func (h HostsList) MarshalYAML() (interface{}, error) {
+	list := h.AsList()
+	sort.Strings(list)
+	return list, nil
+}
+
+func (h HostsList) MarshalJSON() ([]byte, error) {
+	list := h.AsList()
+	sort.Strings(list)
+	return json.Marshal(list)
+}
+
 // LoggingConfig the logging configuration for a service
 type LoggingConfig struct {
 	Driver  string            `yaml:",omitempty" json:"driver,omitempty"`


Test patch:
diff --git a/loader/full-struct_test.go b/loader/full-struct_test.go
index 80d9218..263ef22 100644
--- a/loader/full-struct_test.go
+++ b/loader/full-struct_test.go
@@ -716,8 +716,8 @@ services:
     - project_db_1:mysql
     - project_db_1:postgresql
     extra_hosts:
-      otherhost: 50.31.209.229
-      somehost: 162.242.195.82
+    - otherhost:50.31.209.229
+    - somehost:162.242.195.82
     hostname: foo
     healthcheck:
       test:
@@ -1302,10 +1302,10 @@ func fullExampleJSON(workingDir, homeDir string) string {
         "project_db_1:mysql",
         "project_db_1:postgresql"
       ],
-      "extra_hosts": {
-        "otherhost": "50.31.209.229",
-        "somehost": "162.242.195.82"
-      },
+      "extra_hosts": [
+        "otherhost:50.31.209.229",
+        "somehost:162.242.195.82"
+      ],
       "hostname": "foo",
       "healthcheck": {
         "test": [
Repository: compose-spec/compose-go
Pull request #328 (2022-12-18 12:15:11)

improve warning message
closes https://github.com/docker/compose/issues/10093


Patch:
diff --git a/loader/loader.go b/loader/loader.go
index 784cdb2..4449ba0 100644
--- a/loader/loader.go
+++ b/loader/loader.go
@@ -687,7 +687,7 @@ func resolveVolumePath(volume types.ServiceVolumeConfig, workingDir string, look
 }
 
 func resolveSecretsPath(secret types.SecretConfig, workingDir string, lookupEnv template.Mapping) types.SecretConfig {
-	if ! secret.External.External && secret.File != "" {
+	if !secret.External.External && secret.File != "" {
 		secret.File = resolveMaybeUnixPath(secret.File, workingDir, lookupEnv)
 	}
 	return secret
@@ -741,7 +741,7 @@ func LoadNetworks(source map[string]interface{}) (map[string]types.NetworkConfig
 			if network.Name != "" {
 				return nil, errors.Errorf("network %s: network.external.name and network.name conflict; only use network.name", name)
 			}
-			logrus.Warnf("network %s: network.external.name is deprecated in favor of network.name", name)
+			logrus.Warnf("network %s: network.external.name is deprecated. Please set network.name with external: true", name)
 			network.Name = network.External.Name
 			network.External.Name = ""
 		case network.Name == "":


Test patch:
diff --git a/loader/loader_test.go b/loader/loader_test.go
index 8c1ccec..a755249 100644
--- a/loader/loader_test.go
+++ b/loader/loader_test.go
@@ -1455,7 +1455,7 @@ func TestLoadNetworksWarnOnDeprecatedExternalName(t *testing.T) {
 		},
 	}
 	assert.Check(t, is.DeepEqual(expected, networks))
-	assert.Check(t, strings.Contains(buf.String(), "network foo: network.external.name is deprecated in favor of network.name"))
+	assert.Check(t, strings.Contains(buf.String(), "network foo: network.external.name is deprecated. Please set network.name with external: true"))
 }
 
 func TestLoadNetworkInvalidExternalNameAndNameCombination(t *testing.T) {
@@ -1861,13 +1861,13 @@ func TestLoadWithExtends(t *testing.T) {
 			},
 			Environment: types.MappingWithEquals{},
 			Networks:    map[string]*types.ServiceNetworkConfig{"default": nil},
-			Volumes:     []types.ServiceVolumeConfig{{
+			Volumes: []types.ServiceVolumeConfig{{
 				Type:   "bind",
 				Source: "/opt/data",
 				Target: "/var/lib/mysql",
 				Bind:   &types.ServiceVolumeBind{CreateHostPath: true},
 			}},
-			Scale:       1,
+			Scale: 1,
 		},
 	}
 	assert.Check(t, is.DeepEqual(expServices, actual.Services))
Repository: compose-spec/compose-go
Pull request #332 (2022-12-21 09:15:51)

resolve device path for local bind mount volumes
closes https://github.com/docker/compose/issues/9971

see https://github.com/docker/compose/blob/master/compose/config/config.py#L496-L497


Patch:
diff --git a/loader/normalize.go b/loader/normalize.go
index 4b98d62..00ab009 100644
--- a/loader/normalize.go
+++ b/loader/normalize.go
@@ -110,6 +110,14 @@ func normalize(project *types.Project, resolvePaths bool) error {
 		project.Services[i] = s
 	}
 
+	for name, config := range project.Volumes {
+		if config.Driver == "local" && config.DriverOpts["o"] == "bind" {
+			// This is actually a bind mount
+			config.DriverOpts["device"] = absPath(project.WorkingDir, config.DriverOpts["device"])
+			project.Volumes[name] = config
+		}
+	}
+
 	setNameFromKey(project)
 
 	return nil


Test patch:
diff --git a/loader/loader_test.go b/loader/loader_test.go
index a755249..66a9252 100644
--- a/loader/loader_test.go
+++ b/loader/loader_test.go
@@ -2131,3 +2131,26 @@ services:
 		assert.Equal(t, "env-var-web", svc.ContainerName)
 	})
 }
+
+func TestLoadWithBindMountVolume(t *testing.T) {
+	dict := `
+services:
+  web:
+    image: web
+    volumes:
+     - data:/data
+volumes:
+  data:
+    driver: local
+    driver_opts:
+      type: 'none'
+      o: 'bind'
+      device: './data'
+`
+	configDetails := buildConfigDetails(dict, nil)
+
+	project, err := Load(configDetails)
+	assert.NilError(t, err)
+	path := project.Volumes["data"].DriverOpts["device"]
+	assert.Check(t, filepath.IsAbs(path))
+}