Skip to content

Commit c1b9c79

Browse files
[chore][cmd/mdatagen] Fix RootPackage to use go module root instead of git repo root
1 parent 141db80 commit c1b9c79

3 files changed

Lines changed: 86 additions & 81 deletions

File tree

cmd/mdatagen/internal/command_test.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"go/parser"
1010
"go/token"
1111
"os"
12-
"os/exec"
1312
"path/filepath"
1413
"strings"
1514
"testing"
@@ -280,9 +279,6 @@ func TestRunContents(t *testing.T) {
280279
tmpdir := filepath.Join(t.TempDir(), "shortname")
281280
err := os.MkdirAll(tmpdir, 0o750)
282281
require.NoError(t, err)
283-
// Init a git repo so helpers.RootPackage can resolve the repo root
284-
// when generateConfigGoStruct is called for components with config.
285-
gitInit(t, tmpdir)
286282
ymlContent, err := os.ReadFile(filepath.Join("testdata", tt.yml))
287283
require.NoError(t, err)
288284
metadataFile := filepath.Join(tmpdir, "metadata.yaml")
@@ -526,7 +522,6 @@ func TestGenerateConfigFiles(t *testing.T) {
526522
tmpdir := filepath.Join(root, "shortname")
527523
require.NoError(t, os.MkdirAll(tmpdir, 0o700))
528524

529-
gitInit(t, root)
530525
require.NoError(t, os.WriteFile(filepath.Join(root, "go.mod"), []byte("module testmodule\n"), 0o600))
531526
err := generateConfigFiles(tt.md, tmpdir, "testmodule")
532527
if tt.wantErr {
@@ -544,7 +539,7 @@ func TestGenerateConfigFiles(t *testing.T) {
544539
}
545540

546541
func TestGenerateConfigGoStruct_RootPackageError(t *testing.T) {
547-
// tmpdir is not inside any git repo, so helpers.RootPackage fails
542+
// tmpdir has no go.mod in any ancestor, so helpers.RootPackage fails
548543
md := Metadata{
549544
Type: "test",
550545
PackageName: "shortname",
@@ -557,7 +552,7 @@ func TestGenerateConfigGoStruct_RootPackageError(t *testing.T) {
557552
}
558553

559554
func TestGenerateConfigFiles_GoStructError(t *testing.T) {
560-
// generateConfigGoStruct fails because tmpdir is not inside a git repo
555+
// generateConfigGoStruct fails because tmpdir has no go.mod in any ancestor
561556
md := Metadata{
562557
Type: "test",
563558
PackageName: "shortname",
@@ -1103,11 +1098,3 @@ func TestGenerateConfigSchema_LocalizesSameRootRefs(t *testing.T) {
11031098
require.Contains(t, string(actual), "$ref: /filter.config")
11041099
require.NotContains(t, string(actual), "$ref: go.opentelemetry.io/collector/filter.config")
11051100
}
1106-
1107-
func gitInit(t *testing.T, dir string) {
1108-
t.Helper()
1109-
cmd := exec.Command("git", "init")
1110-
cmd.Dir = dir
1111-
out, err := cmd.CombinedOutput()
1112-
require.NoError(t, err, "git init failed: %s", out)
1113-
}

cmd/mdatagen/internal/helpers/packages.go

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,52 @@
44
package helpers // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/helpers"
55

66
import (
7-
"errors"
87
"fmt"
98
"os"
109
"os/exec"
1110
"path/filepath"
1211
"strings"
1312
)
1413

15-
// RootPackage determines the root Go module path by reading the module directive
16-
// from the go.mod at the repository root. This is used to resolve local absolute
17-
// references (e.g., "/config/confighttp.client_config") into full Go import paths.
14+
// RootPackage determines the root Go module path by finding the highest go.mod above componentDir
15+
// and running "go list -m" in that directory. This is used to resolve local absolute references
16+
// (e.g., "/config/confighttp.client_config") into full Go import paths.
1817
func RootPackage(componentDir string) (string, error) {
19-
repoRoot, err := repoRoot(componentDir)
18+
rootModDir, err := rootModuleDir(componentDir)
2019
if err != nil {
2120
return "", err
2221
}
2322

24-
goModData, err := os.ReadFile(filepath.Clean(filepath.Join(repoRoot, "go.mod")))
23+
cmd := exec.Command("go", "list", "-m")
24+
cmd.Dir = rootModDir
25+
output, err := cmd.Output()
26+
if err != nil {
27+
return "", fmt.Errorf("failed to resolve root module path: %w", err)
28+
}
29+
return strings.TrimSpace(string(output)), nil
30+
}
31+
32+
func rootModuleDir(componentDir string) (string, error) {
33+
absDir, err := filepath.Abs(componentDir)
2534
if err != nil {
26-
return "", fmt.Errorf("failed to read root go.mod: %w", err)
35+
return "", fmt.Errorf("failed to get absolute path: %w", err)
2736
}
2837

29-
for line := range strings.SplitSeq(string(goModData), "\n") {
30-
if after, ok := strings.CutPrefix(strings.TrimSpace(line), "module "); ok {
31-
return strings.TrimSpace(after), nil
38+
var found string
39+
dir := absDir
40+
for {
41+
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
42+
found = dir
3243
}
44+
parent := filepath.Dir(dir)
45+
if parent == dir {
46+
break
47+
}
48+
dir = parent
3349
}
34-
return "", errors.New("module directive not found in root go.mod")
35-
}
3650

37-
func repoRoot(dir string) (string, error) {
38-
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
39-
cmd.Dir = dir
40-
output, err := cmd.Output()
41-
if err != nil {
42-
return "", fmt.Errorf("failed to find repo root: %w", err)
51+
if found == "" {
52+
return "", fmt.Errorf("no go.mod found in any parent of %s", componentDir)
4353
}
44-
return strings.TrimSpace(string(output)), nil
54+
return found, nil
4555
}

cmd/mdatagen/internal/helpers/packages_test.go

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,62 @@ package helpers
55

66
import (
77
"os"
8-
"os/exec"
98
"path/filepath"
109
"testing"
1110

1211
"github.com/stretchr/testify/assert"
1312
"github.com/stretchr/testify/require"
1413
)
1514

16-
func TestRepoRoot(t *testing.T) {
17-
t.Run("returns_repo_root_from_subdirectory", func(t *testing.T) {
18-
wd, err := os.Getwd()
15+
func TestRootModuleDir(t *testing.T) {
16+
t.Run("finds_go_mod_in_parent", func(t *testing.T) {
17+
tmp := t.TempDir()
18+
subDir := filepath.Join(tmp, "sub")
19+
require.NoError(t, os.MkdirAll(subDir, 0o700))
20+
21+
require.NoError(t, os.WriteFile(filepath.Join(tmp, "go.mod"), []byte("module example.com/root\n"), 0o600))
22+
23+
dir, err := rootModuleDir(subDir)
1924
require.NoError(t, err)
25+
assert.Equal(t, tmp, dir)
26+
})
27+
28+
t.Run("finds_go_mod_in_intermediate_directory", func(t *testing.T) {
29+
tmp := t.TempDir()
30+
projectDir := filepath.Join(tmp, "project")
31+
componentDir := filepath.Join(projectDir, "receiver", "foo")
32+
require.NoError(t, os.MkdirAll(componentDir, 0o700))
2033

21-
root, err := repoRoot(wd)
34+
// No go.mod at tmp root; go.mod is in project/ subdirectory
35+
require.NoError(t, os.WriteFile(filepath.Join(projectDir, "go.mod"), []byte("module example.com/project\n"), 0o600))
36+
37+
dir, err := rootModuleDir(componentDir)
2238
require.NoError(t, err)
23-
assert.DirExists(t, root)
24-
assert.FileExists(t, filepath.Join(root, "go.mod"))
39+
assert.Equal(t, projectDir, dir)
2540
})
2641

27-
t.Run("error_for_nonexistent_directory", func(t *testing.T) {
28-
_, err := repoRoot("/nonexistent/path/that/does/not/exist")
29-
require.Error(t, err)
42+
t.Run("prefers_highest_go_mod", func(t *testing.T) {
43+
tmp := t.TempDir()
44+
componentDir := filepath.Join(tmp, "project", "receiver", "foo")
45+
require.NoError(t, os.MkdirAll(componentDir, 0o700))
46+
47+
// go.mod at both levels
48+
require.NoError(t, os.WriteFile(filepath.Join(tmp, "go.mod"), []byte("module example.com/root\n"), 0o600))
49+
require.NoError(t, os.WriteFile(filepath.Join(tmp, "project", "go.mod"), []byte("module example.com/project\n"), 0o600))
50+
51+
dir, err := rootModuleDir(componentDir)
52+
require.NoError(t, err)
53+
assert.Equal(t, tmp, dir)
3054
})
3155

32-
t.Run("error_outside_git_repo", func(t *testing.T) {
56+
t.Run("error_when_no_go_mod_found", func(t *testing.T) {
3357
tmp := t.TempDir()
34-
_, err := repoRoot(tmp)
58+
subDir := filepath.Join(tmp, "sub")
59+
require.NoError(t, os.MkdirAll(subDir, 0o700))
60+
61+
_, err := rootModuleDir(subDir)
3562
require.Error(t, err)
63+
assert.Contains(t, err.Error(), "no go.mod found")
3664
})
3765
}
3866

@@ -51,57 +79,37 @@ func TestRootPackage(t *testing.T) {
5179
require.Error(t, err)
5280
})
5381

54-
t.Run("error_when_go_mod_missing", func(t *testing.T) {
82+
t.Run("resolves_module_from_synthetic_go_mod", func(t *testing.T) {
5583
tmp := t.TempDir()
56-
subDir := filepath.Join(tmp, "sub")
57-
require.NoError(t, os.MkdirAll(subDir, 0o700))
58-
59-
gitInit(t, tmp)
60-
61-
_, err := RootPackage(subDir)
62-
require.Error(t, err)
63-
assert.Contains(t, err.Error(), "go.mod")
64-
})
65-
66-
t.Run("error_when_go_mod_has_no_module_directive", func(t *testing.T) {
67-
tmp := t.TempDir()
68-
subDir := filepath.Join(tmp, "sub")
84+
subDir := filepath.Join(tmp, "pkg", "foo")
6985
require.NoError(t, os.MkdirAll(subDir, 0o700))
7086

71-
gitInit(t, tmp)
7287
require.NoError(t, os.WriteFile(
7388
filepath.Join(tmp, "go.mod"),
74-
[]byte("go 1.21\n"),
89+
[]byte("module example.com/my-project\n\ngo 1.21\n"),
7590
0o600,
7691
))
7792

78-
_, err := RootPackage(subDir)
79-
require.Error(t, err)
80-
assert.Contains(t, err.Error(), "module directive not found")
93+
pkg, err := RootPackage(subDir)
94+
require.NoError(t, err)
95+
assert.Equal(t, "example.com/my-project", pkg)
8196
})
8297

83-
t.Run("parses_module_from_synthetic_go_mod", func(t *testing.T) {
98+
t.Run("monorepo_go_mod_not_at_top_level", func(t *testing.T) {
8499
tmp := t.TempDir()
85-
subDir := filepath.Join(tmp, "pkg", "foo")
86-
require.NoError(t, os.MkdirAll(subDir, 0o700))
100+
projectDir := filepath.Join(tmp, "collector")
101+
componentDir := filepath.Join(projectDir, "receiver", "foo")
102+
require.NoError(t, os.MkdirAll(componentDir, 0o700))
87103

88-
gitInit(t, tmp)
104+
// No go.mod at top level; only in collector/ subdirectory
89105
require.NoError(t, os.WriteFile(
90-
filepath.Join(tmp, "go.mod"),
91-
[]byte("module example.com/my-project\n\ngo 1.21\n"),
106+
filepath.Join(projectDir, "go.mod"),
107+
[]byte("module go.opentelemetry.io/collector\n\ngo 1.21\n"),
92108
0o600,
93109
))
94110

95-
pkg, err := RootPackage(subDir)
111+
pkg, err := RootPackage(componentDir)
96112
require.NoError(t, err)
97-
assert.Equal(t, "example.com/my-project", pkg)
113+
assert.Equal(t, "go.opentelemetry.io/collector", pkg)
98114
})
99115
}
100-
101-
func gitInit(t *testing.T, dir string) {
102-
t.Helper()
103-
cmd := exec.Command("git", "init")
104-
cmd.Dir = dir
105-
out, err := cmd.CombinedOutput()
106-
require.NoError(t, err, "git init failed: %s", out)
107-
}

0 commit comments

Comments
 (0)