Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
17 changes: 13 additions & 4 deletions util/git/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,14 @@ func (m *nativeGitClient) Fetch(revision string) error {
func (m *nativeGitClient) LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (m *nativeGitClient) LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error) {
func (m *nativeGitClient) LsFiles(pattern string, enableNewGitFileGlobbing bool) ([]string, error) {

Shouldn't this be pattern instead?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it can be either. it depends on what is put inside the applicationset, but the globs are still representing a path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both names are fine by me. I can change it to pattern if you think it's better, lmk

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look at the applicationset code, especially this, it is a little confusing whether it's pattern or path.

@rumstead rumstead May 7, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's based on what the user provides in their applicationset, it can be either a path or a path glob. we use the term path in the git generator. i would suggest it stays the same.

if enableNewGitFileGlobbing {
// This is the new way with safer globbing
err := os.Chdir(m.root)

// evaluating the root path for symlinks
realRoot, err := filepath.EvalSymlinks(m.root)
if err != nil {
return nil, err
}
allFiles, err := doublestar.FilepathGlob(path)
// searching for the pattern inside the root path
allFiles, err := doublestar.FilepathGlob(filepath.Join(realRoot, path))
if err != nil {
return nil, err
}
Expand All @@ -440,8 +443,14 @@ func (m *nativeGitClient) LsFiles(path string, enableNewGitFileGlobbing bool) ([
if err != nil {
return nil, err
}
if strings.HasPrefix(absPath, m.root) {
files = append(files, file)

if strings.HasPrefix(absPath, realRoot) {
// removing the repository root prefix from the file path
relativeFile, err := filepath.Rel(realRoot, file)
if err != nil {
return nil, err
}
files = append(files, relativeFile)
} else {
log.Warnf("Absolute path for %s is outside of repository, removing it", file)
Comment thread
magat marked this conversation as resolved.
Outdated
}
Expand Down
60 changes: 60 additions & 0 deletions util/git/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path"
"path/filepath"
"strings"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -993,6 +994,65 @@ func Test_nativeGitClient_runCredentialedCmd(t *testing.T) {
}
}

func Test_LsFiles_RaceCondition(t *testing.T) {
// Create two temporary directories and initialize them as git repositories
tempDir1 := t.TempDir()
tempDir2 := t.TempDir()

client1, err := NewClient("file://"+tempDir1, NopCreds{}, true, false, "", "")
require.NoError(t, err)
client2, err := NewClient("file://"+tempDir2, NopCreds{}, true, false, "", "")
require.NoError(t, err)

err = client1.Init()
require.NoError(t, err)
err = client2.Init()
require.NoError(t, err)

// Add different files to each repository
file1 := filepath.Join(client1.Root(), "file1.txt")
err = os.WriteFile(file1, []byte("content1"), 0o644)
require.NoError(t, err)
err = runCmd(client1.Root(), "git", "add", "file1.txt")
require.NoError(t, err)
err = runCmd(client1.Root(), "git", "commit", "-m", "Add file1")
require.NoError(t, err)

file2 := filepath.Join(client2.Root(), "file2.txt")
err = os.WriteFile(file2, []byte("content2"), 0o644)
require.NoError(t, err)
err = runCmd(client2.Root(), "git", "add", "file2.txt")
require.NoError(t, err)
err = runCmd(client2.Root(), "git", "commit", "-m", "Add file2")
require.NoError(t, err)

// Assert that LsFiles returns the correct files when called sequentially
files1, err := client1.LsFiles("*", true)
require.NoError(t, err)
require.Contains(t, files1, "file1.txt")

files2, err := client2.LsFiles("*", true)
require.NoError(t, err)
require.Contains(t, files2, "file2.txt")

// Define a function to call LsFiles multiple times in parallel
var wg sync.WaitGroup
callLsFiles := func(client Client, expectedFile string) {
defer wg.Done()
for i := 0; i < 100; i++ {
files, err := client.LsFiles("*", true)
require.NoError(t, err)
require.Contains(t, files, expectedFile)
}
}

// Call LsFiles in parallel for both clients
wg.Add(2)
go callLsFiles(client1, "file1.txt")
go callLsFiles(client2, "file2.txt")
wg.Wait()
}

type mockCreds struct {
environ []string
environErr bool
Expand Down