diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 575ecf2..593bb97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,11 @@ permissions: {} jobs: test: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: diff --git a/fs_test.go b/fs_test.go index 27e9875..65698e9 100644 --- a/fs_test.go +++ b/fs_test.go @@ -3,6 +3,7 @@ package clone import ( "os" "path/filepath" + "runtime" "testing" ) @@ -35,7 +36,7 @@ func TestCopyTreeCopiesFilesDirectoriesAndSymlinks(t *testing.T) { if err != nil { t.Fatal(err) } - if info.Mode().Perm() != 0o600 { + if runtime.GOOS != "windows" && info.Mode().Perm() != 0o600 { t.Errorf("file mode = %o, want 600", info.Mode().Perm()) } link, err := os.Readlink(filepath.Join(dst, "link")) diff --git a/gogit/blob_test.go b/gogit/blob_test.go index a099da9..d1bd8f3 100644 --- a/gogit/blob_test.go +++ b/gogit/blob_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "errors" + "fmt" "os" "os/exec" "path/filepath" @@ -280,7 +281,9 @@ func TestBlobPreservesGoGitAndGitErrors(t *testing.T) { if !errors.Is(err, exec.ErrNotFound) { t.Errorf("error = %v, want exec.ErrNotFound", err) } - if err == nil || !strings.Contains(err.Error(), dir) { + // The go-git error renders the path with %q, so match the quoted + // form; on Windows the escaping doubles the backslashes. + if err == nil || !strings.Contains(err.Error(), fmt.Sprintf("%q", dir)) { t.Errorf("error = %v, want starting path %q", err, dir) } } diff --git a/run_test.go b/run_test.go index 6c309b6..a20d557 100644 --- a/run_test.go +++ b/run_test.go @@ -34,20 +34,22 @@ func TestRemoteEnv(t *testing.T) { func TestRunUsesDirectoryAndEnvironment(t *testing.T) { requireGit(t) dir := t.TempDir() + // A marker file read relative to the working directory proves dir is + // used without comparing path spellings, which differ under git's + // MSYS shell on Windows. + if err := os.WriteFile(filepath.Join(dir, "marker"), []byte("in-dir"), 0o644); err != nil { + t.Fatal(err) + } out, err := Run(context.Background(), dir, []string{"CLONE_RUN_TEST=value"}, - "-c", "alias.test=!pwd && printf \"|%s\" \"$CLONE_RUN_TEST\"", "test") + "-c", "alias.test=!cat marker && printf \"|%s\" \"$CLONE_RUN_TEST\"", "test") if err != nil { t.Fatalf("Run: %s: %v", out, err) } parts := strings.Split(strings.TrimSpace(out), "|") - resolvedDir, err := filepath.EvalSymlinks(dir) - if err != nil { - t.Fatal(err) - } if len(parts) != 2 || - strings.TrimSpace(parts[0]) != resolvedDir || + strings.TrimSpace(parts[0]) != "in-dir" || strings.TrimSpace(parts[1]) != "value" { - t.Fatalf("Run output = %q, want %q and environment value", out, dir) + t.Fatalf("Run output = %q, want marker content and environment value", out) } } diff --git a/test_helpers_test.go b/test_helpers_test.go index af10aa7..708ce99 100644 --- a/test_helpers_test.go +++ b/test_helpers_test.go @@ -7,6 +7,22 @@ import ( "testing" ) +// The library runs git with the ambient environment, so system and global +// config (core.autocrlf=true on Windows runners) leaks into checkouts made +// by the code under test. Isolate the whole test process, not just the +// fixture helpers. +func TestMain(m *testing.M) { + for key, value := range map[string]string{ + "GIT_CONFIG_NOSYSTEM": "1", + "GIT_CONFIG_GLOBAL": os.DevNull, + } { + if err := os.Setenv(key, value); err != nil { + panic(err) + } + } + os.Exit(m.Run()) +} + func requireGit(t testing.TB) { t.Helper() if _, err := exec.LookPath("git"); err != nil {