Skip to content

Commit 6f87394

Browse files
Improve submodule test: create proper gitlink and verify clone
- CreateGitServerWithSubmodule now creates a proper git submodule with: - .gitmodules file - Submodule config in .git/config - Gitlink entry (mode 160000) in the index pointing to submodule commit - Add CommitSubmodule helper to create proper submodule entries - Update TestGitSubmodules to verify the submodule file is actually cloned, not just that .gitmodules exists
1 parent 92f5137 commit 6f87394

2 files changed

Lines changed: 90 additions & 15 deletions

File tree

integration/integration_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ func TestGitSubmodules(t *testing.T) {
422422
t.Parallel()
423423

424424
// Create parent repo with a submodule
425-
parentSrv, submoduleSrv := gittest.CreateGitServerWithSubmodule(t, gittest.Options{
425+
parentSrv, _ := gittest.CreateGitServerWithSubmodule(t, gittest.Options{
426426
Files: map[string]string{
427427
"Dockerfile": "FROM " + testImageAlpine,
428428
},
@@ -442,7 +442,10 @@ func TestGitSubmodules(t *testing.T) {
442442
// Verify the .gitmodules file exists
443443
gitmodules := execContainer(t, ctr, "cat /workspaces/empty/.gitmodules")
444444
require.Contains(t, gitmodules, "[submodule")
445-
require.Contains(t, gitmodules, submoduleSrv.URL)
445+
446+
// Verify the submodule was actually cloned by checking for the file inside it
447+
subfileContent := execContainer(t, ctr, "cat /workspaces/empty/submod/subfile.txt")
448+
require.Contains(t, subfileContent, "submodule content")
446449
}
447450

448451
func TestGitSSHAuth(t *testing.T) {

testutil/gittest/gittest.go

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ import (
2020
"github.com/go-git/go-billy/v5"
2121
"github.com/go-git/go-billy/v5/memfs"
2222
"github.com/go-git/go-git/v5"
23+
"github.com/go-git/go-git/v5/config"
2324
"github.com/go-git/go-git/v5/plumbing"
2425
"github.com/go-git/go-git/v5/plumbing/cache"
26+
"github.com/go-git/go-git/v5/plumbing/filemode"
27+
"github.com/go-git/go-git/v5/plumbing/format/index"
2528
"github.com/go-git/go-git/v5/plumbing/format/pktline"
2629
"github.com/go-git/go-git/v5/plumbing/object"
2730
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
@@ -272,38 +275,107 @@ func NewRepo(t *testing.T, fs billy.Filesystem, commits ...CommitFunc) *git.Repo
272275

273276
// CreateGitServerWithSubmodule creates a parent git repo with a submodule pointing to another repo.
274277
// Returns the parent server and the submodule server.
278+
// The submodule is properly registered with a gitlink entry in the tree.
275279
func CreateGitServerWithSubmodule(t *testing.T, opts Options, submoduleOpts Options) (parentSrv *httptest.Server, submoduleSrv *httptest.Server) {
276280
t.Helper()
277281

278-
// Create the submodule repo first
279-
submoduleSrv = CreateGitServer(t, submoduleOpts)
282+
// Create the submodule repo first and get its HEAD commit
283+
submoduleFS := memfs.New()
284+
submoduleCommits := make([]CommitFunc, 0)
285+
for path, content := range submoduleOpts.Files {
286+
submoduleCommits = append(submoduleCommits, Commit(t, path, content, "submodule commit"))
287+
}
288+
submoduleRepo := NewRepo(t, submoduleFS, submoduleCommits...)
289+
290+
// Get the submodule's HEAD commit hash
291+
submoduleHead, err := submoduleRepo.Head()
292+
require.NoError(t, err)
293+
submoduleHash := submoduleHead.Hash()
294+
295+
// Start the submodule server
296+
if submoduleOpts.AuthMW == nil {
297+
submoduleOpts.AuthMW = mwtest.BasicAuthMW(submoduleOpts.Username, submoduleOpts.Password)
298+
}
299+
if submoduleOpts.TLS {
300+
submoduleSrv = httptest.NewTLSServer(submoduleOpts.AuthMW(NewServer(submoduleFS)))
301+
} else {
302+
submoduleSrv = httptest.NewServer(submoduleOpts.AuthMW(NewServer(submoduleFS)))
303+
}
280304

281-
// Create the parent repo with .gitmodules pointing to submodule
305+
// Create the parent repo with .gitmodules and gitlink entry
282306
if opts.AuthMW == nil {
283307
opts.AuthMW = mwtest.BasicAuthMW(opts.Username, opts.Password)
284308
}
285309

286-
fs := memfs.New()
310+
parentFS := memfs.New()
287311
commits := make([]CommitFunc, 0)
288312
for path, content := range opts.Files {
289313
commits = append(commits, Commit(t, path, content, "my test commit"))
290314
}
291-
// Add gitmodules file pointing to the submodule server
292-
gitmodulesContent := fmt.Sprintf(`[submodule "submod"]
293-
path = submod
294-
url = %s
295-
`, submoduleSrv.URL)
296-
commits = append(commits, Commit(t, ".gitmodules", gitmodulesContent, "add submodule"))
297-
_ = NewRepo(t, fs, commits...)
315+
316+
// Add .gitmodules file and gitlink entry for the submodule
317+
commits = append(commits, CommitSubmodule(t, "submod", submoduleSrv.URL, submoduleHash))
318+
319+
_ = NewRepo(t, parentFS, commits...)
298320

299321
if opts.TLS {
300-
parentSrv = httptest.NewTLSServer(opts.AuthMW(NewServer(fs)))
322+
parentSrv = httptest.NewTLSServer(opts.AuthMW(NewServer(parentFS)))
301323
} else {
302-
parentSrv = httptest.NewServer(opts.AuthMW(NewServer(fs)))
324+
parentSrv = httptest.NewServer(opts.AuthMW(NewServer(parentFS)))
303325
}
304326
return parentSrv, submoduleSrv
305327
}
306328

329+
// CommitSubmodule creates a commit that adds a submodule with proper .gitmodules and gitlink entry.
330+
func CommitSubmodule(t *testing.T, path, url string, hash plumbing.Hash) CommitFunc {
331+
return func(fs billy.Filesystem, repo *git.Repository) {
332+
t.Helper()
333+
tree, err := repo.Worktree()
334+
require.NoError(t, err)
335+
336+
// Create .gitmodules file
337+
gitmodulesContent := fmt.Sprintf("[submodule %q]\n\tpath = %s\n\turl = %s\n", path, path, url)
338+
WriteFile(t, fs, ".gitmodules", gitmodulesContent)
339+
_, err = tree.Add(".gitmodules")
340+
require.NoError(t, err)
341+
342+
// Add submodule config to .git/config
343+
cfg, err := repo.Config()
344+
require.NoError(t, err)
345+
cfg.Submodules[path] = &config.Submodule{
346+
Name: path,
347+
Path: path,
348+
URL: url,
349+
}
350+
err = repo.SetConfig(cfg)
351+
require.NoError(t, err)
352+
353+
// Create the gitlink entry (mode 160000 commit reference)
354+
// We need to add it directly to the index
355+
idx, err := repo.Storer.Index()
356+
require.NoError(t, err)
357+
358+
// Add a gitlink entry - this is a special index entry with mode 160000
359+
idx.Entries = append(idx.Entries, &index.Entry{
360+
Mode: filemode.Submodule,
361+
Hash: hash,
362+
Name: path,
363+
})
364+
err = repo.Storer.SetIndex(idx)
365+
require.NoError(t, err)
366+
367+
// Commit the changes
368+
_, err = tree.Commit("add submodule", &git.CommitOptions{
369+
Author: &object.Signature{
370+
Name: "Example",
371+
Email: "test@example.com",
372+
When: time.Now(),
373+
},
374+
})
375+
require.NoError(t, err)
376+
}
377+
}
378+
307379
// WriteFile writes a file to the filesystem.
308380
func WriteFile(t *testing.T, fs billy.Filesystem, path, content string) {
309381
t.Helper()

0 commit comments

Comments
 (0)