Skip to content

[cmd/mdatagen]: Improve loading errors for clarity #13206

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

Merged
merged 8 commits into from
Jun 20, 2025
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .chloggen/alder_improve-mdatagen-errors.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: 'enhancement'

# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver)
component: mdatagen

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "Taught mdatagen to print the `go list` stderr output on failures, and to run `go list` where the metadata file is."

# One or more tracking issues or pull requests related to the change
issues: [13205]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user]
2 changes: 2 additions & 0 deletions cmd/mdatagen/internal/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ func TestRunContents(t *testing.T) {
require.NoError(t, err)
metadataFile := filepath.Join(tmpdir, "metadata.yaml")
require.NoError(t, os.WriteFile(metadataFile, ymlContent, 0o600))
require.NoError(t, os.WriteFile(filepath.Join(tmpdir, "empty.go"), []byte("package shortname"), 0o600))
require.NoError(t, os.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte("module shortname"), 0o600))
require.NoError(t, os.WriteFile(filepath.Join(tmpdir, "README.md"), []byte(`
<!-- status autogenerated section -->
foo
Expand Down
14 changes: 11 additions & 3 deletions cmd/mdatagen/internal/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import (
"context"
"errors"
"fmt"
"os/exec"
"path/filepath"
"strings"
Expand Down Expand Up @@ -42,7 +44,7 @@
return md, err
}
if md.ScopeName == "" {
md.ScopeName, err = packageName()
md.ScopeName, err = packageName(filepath.Dir(filePath))
if err != nil {
return md, err
}
Expand Down Expand Up @@ -80,11 +82,17 @@
return parentFolder
}

func packageName() (string, error) {
func packageName(filePath string) (string, error) {
cmd := exec.Command("go", "list", "-f", "{{.ImportPath}}")
cmd.Dir = filePath
output, err := cmd.Output()
if err != nil {
return "", err
var ee *exec.ExitError
if errors.As(err, &ee) {
return "", fmt.Errorf("unable to determine package name: %v failed: (stderr) %v", cmd.Args, string(ee.Stderr))
}

return "", fmt.Errorf("unable to determine package name: %v failed: %v %w", cmd.Args, string(output), err)

Check warning on line 95 in cmd/mdatagen/internal/loader.go

View check run for this annotation

Codecov / codecov/patch

cmd/mdatagen/internal/loader.go#L95

Added line #L95 was not covered by tests
}
return strings.TrimSpace(string(output)), nil
}
30 changes: 26 additions & 4 deletions cmd/mdatagen/internal/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package internal

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -13,6 +15,22 @@ import (
"go.opentelemetry.io/collector/pdata/pmetric"
)

func TestTwoPackagesInDirectory(t *testing.T) {
contents, err := os.ReadFile("testdata/twopackages.yaml")
require.NoError(t, err)
tempDir := t.TempDir()
metadataPath := filepath.Join(tempDir, "metadata.yaml")
// we create a trivial module and packages to avoid having invalid go checked into our test directory.
require.NoError(t, os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte("module twopackages"), 0o600))
require.NoError(t, os.WriteFile(filepath.Join(tempDir, "package1.go"), []byte("package package1"), 0o600))
require.NoError(t, os.WriteFile(filepath.Join(tempDir, "package2.go"), []byte("package package2"), 0o600))
require.NoError(t, os.WriteFile(metadataPath, contents, 0o600))

_, err = LoadMetadata(metadataPath)
require.Error(t, err)
require.ErrorContains(t, err, "unable to determine package name: [go list -f {{.ImportPath}}] failed: (stderr) found packages package1 (package1.go) and package2 (package2.go)")
}

func TestLoadMetadata(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -348,7 +366,7 @@ func TestLoadMetadata(t *testing.T) {
Type: "subcomponent",
Parent: "parentComponent",
GeneratedPackageName: "metadata",
ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal",
ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata",
ShortFolderName: "testdata",
Tests: Tests{Host: "componenttest.NewNopHost()"},
},
Expand All @@ -358,7 +376,7 @@ func TestLoadMetadata(t *testing.T) {
want: Metadata{
Type: "custom",
GeneratedPackageName: "customname",
ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal",
ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata",
ShortFolderName: "testdata",
Tests: Tests{Host: "componenttest.NewNopHost()"},
Status: &Status{
Expand All @@ -376,7 +394,7 @@ func TestLoadMetadata(t *testing.T) {
want: Metadata{
Type: "test",
GeneratedPackageName: "metadata",
ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal",
ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata",
ShortFolderName: "testdata",
Tests: Tests{Host: "componenttest.NewNopHost()"},
Status: &Status{
Expand Down Expand Up @@ -422,13 +440,17 @@ func TestLoadMetadata(t *testing.T) {
want: Metadata{},
wantErr: "decoding failed due to the following error(s):\n\nerror decoding 'attributes[used_attr].type': invalid type: \"invalidtype\"",
},
{
name: "testdata/~~this file doesn't exist~~.yaml",
wantErr: "unable to read the file file:testdata/~~this file doesn't exist~~.yaml",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := LoadMetadata(tt.name)
if tt.wantErr != "" {
require.Error(t, err)
require.EqualError(t, err, tt.wantErr)
require.ErrorContains(t, err, tt.wantErr)
} else {
require.NoError(t, err)
require.Equal(t, tt.want, got)
Expand Down
6 changes: 6 additions & 0 deletions cmd/mdatagen/internal/testdata/empty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package testdata

// this file allows `go list -f` to run in tests and get the scope name.
6 changes: 6 additions & 0 deletions cmd/mdatagen/internal/testdata/events/empty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package events

// this file allows `go list -f` to run in tests and get the scope name.
7 changes: 7 additions & 0 deletions cmd/mdatagen/internal/testdata/twopackages.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type: sample
github_project: open-telemetry/opentelemetry-collector

status:
class: receiver
stability:
beta: [traces]
Loading