Skip to content

Commit 83ccf98

Browse files
authored
Merge pull request #2 from hashicorp/main
rebase or main repo
2 parents e484031 + 5a63fd9 commit 83ccf98

File tree

2 files changed

+186
-15
lines changed

2 files changed

+186
-15
lines changed

get_git.go

+67-14
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func (g *GitGetter) Get(dst string, u *url.URL) error {
125125
return err
126126
}
127127
if err == nil {
128-
err = g.update(ctx, dst, sshKeyFile, ref, depth)
128+
err = g.update(ctx, dst, sshKeyFile, u, ref, depth)
129129
} else {
130130
err = g.clone(ctx, dst, sshKeyFile, u, ref, depth)
131131
}
@@ -228,28 +228,64 @@ func (g *GitGetter) clone(ctx context.Context, dst, sshKeyFile string, u *url.UR
228228
return nil
229229
}
230230

231-
func (g *GitGetter) update(ctx context.Context, dst, sshKeyFile, ref string, depth int) error {
232-
// Determine if we're a branch. If we're NOT a branch, then we just
233-
// switch to master prior to checking out
234-
cmd := exec.CommandContext(ctx, "git", "show-ref", "-q", "--verify", "refs/heads/"+ref)
231+
func (g *GitGetter) update(ctx context.Context, dst, sshKeyFile string, u *url.URL, ref string, depth int) error {
232+
// Remove all variations of .git directories
233+
err := removeCaseInsensitiveGitDirectory(dst)
234+
if err != nil {
235+
return err
236+
}
237+
238+
// Initialize the git repository
239+
cmd := exec.CommandContext(ctx, "git", "init")
240+
cmd.Dir = dst
241+
err = getRunCommand(cmd)
242+
if err != nil {
243+
return err
244+
}
245+
246+
// Add the git remote
247+
cmd = exec.CommandContext(ctx, "git", "remote", "add", "origin", "--", u.String())
248+
cmd.Dir = dst
249+
err = getRunCommand(cmd)
250+
if err != nil {
251+
return err
252+
}
253+
254+
// Fetch the remote ref
255+
cmd = exec.CommandContext(ctx, "git", "fetch", "--tags")
256+
cmd.Dir = dst
257+
err = getRunCommand(cmd)
258+
if err != nil {
259+
return err
260+
}
261+
262+
// Fetch the remote ref
263+
cmd = exec.CommandContext(ctx, "git", "fetch", "origin", "--", ref)
235264
cmd.Dir = dst
265+
err = getRunCommand(cmd)
266+
if err != nil {
267+
return err
268+
}
236269

237-
if getRunCommand(cmd) != nil {
238-
// Not a branch, switch to default branch. This will also catch
239-
// non-existent branches, in which case we want to switch to default
240-
// and then checkout the proper branch later.
241-
ref = findDefaultBranch(ctx, dst)
270+
// Reset the branch to the fetched ref
271+
cmd = exec.CommandContext(ctx, "git", "reset", "--hard", "FETCH_HEAD")
272+
cmd.Dir = dst
273+
err = getRunCommand(cmd)
274+
if err != nil {
275+
return err
242276
}
243277

244-
// We have to be on a branch to pull
245-
if err := g.checkout(ctx, dst, ref); err != nil {
278+
// Checkout ref branch
279+
err = g.checkout(ctx, dst, ref)
280+
if err != nil {
246281
return err
247282
}
248283

284+
// Pull the latest changes from the ref branch
249285
if depth > 0 {
250-
cmd = exec.CommandContext(ctx, "git", "pull", "--depth", strconv.Itoa(depth), "--ff-only")
286+
cmd = exec.CommandContext(ctx, "git", "pull", "origin", "--depth", strconv.Itoa(depth), "--ff-only", "--", ref)
251287
} else {
252-
cmd = exec.CommandContext(ctx, "git", "pull", "--ff-only")
288+
cmd = exec.CommandContext(ctx, "git", "pull", "origin", "--ff-only", "--", ref)
253289
}
254290

255291
cmd.Dir = dst
@@ -377,3 +413,20 @@ func checkGitVersion(ctx context.Context, min string) error {
377413

378414
return nil
379415
}
416+
417+
// removeCaseInsensitiveGitDirectory removes all .git directory variations
418+
func removeCaseInsensitiveGitDirectory(dst string) error {
419+
files, err := os.ReadDir(dst)
420+
if err != nil {
421+
return fmt.Errorf("Failed to read the destination directory %s during git update", dst)
422+
}
423+
for _, f := range files {
424+
if strings.EqualFold(f.Name(), ".git") && f.IsDir() {
425+
err := os.RemoveAll(filepath.Join(dst, f.Name()))
426+
if err != nil {
427+
return fmt.Errorf("Failed to remove the .git directory in the destination directory %s during git update", dst)
428+
}
429+
}
430+
}
431+
return nil
432+
}

get_git_test.go

+119-1
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ func TestGitGetter_remoteWithoutMaster(t *testing.T) {
169169
t.Fatalf("err: %s", err)
170170
}
171171

172+
dst2 := tempDir(t)
172173
// Get again should work
173-
if err := g.Get(dst, repo.url); err != nil {
174+
if err := g.Get(dst2, repo.url); err != nil {
174175
t.Fatalf("err: %s", err)
175176
}
176177

@@ -866,6 +867,123 @@ func TestGitGetter_BadRemoteUrl(t *testing.T) {
866867
}
867868
}
868869

870+
func TestGitGetter_BadGitConfig(t *testing.T) {
871+
if !testHasGit {
872+
t.Log("git not found, skipping")
873+
t.Skip()
874+
}
875+
876+
ctx := context.Background()
877+
g := new(GitGetter)
878+
dst := tempDir(t)
879+
880+
url, err := url.Parse("https://github.com/hashicorp/go-getter")
881+
if err != nil {
882+
t.Fatal(err)
883+
}
884+
885+
_, err = os.Stat(dst)
886+
if err != nil && !os.IsNotExist(err) {
887+
t.Fatalf(err.Error())
888+
}
889+
if err == nil {
890+
// Update the repository containing the bad git config.
891+
// This should remove the bad git config file and initialize a new one.
892+
err = g.update(ctx, dst, testGitToken, url, "main", 1)
893+
} else {
894+
// Clone a repository with a git config file
895+
err = g.clone(ctx, dst, testGitToken, url, "main", 1)
896+
if err != nil {
897+
t.Fatalf(err.Error())
898+
}
899+
900+
// Edit the git config file to simulate a bad git config
901+
gitConfigPath := filepath.Join(dst, ".git", "config")
902+
err = os.WriteFile(gitConfigPath, []byte("bad config"), 0600)
903+
if err != nil {
904+
t.Fatalf(err.Error())
905+
}
906+
907+
// Update the repository containing the bad git config.
908+
// This should remove the bad git config file and initialize a new one.
909+
err = g.update(ctx, dst, testGitToken, url, "main", 1)
910+
}
911+
if err != nil {
912+
t.Fatalf(err.Error())
913+
}
914+
915+
// Check if the .git/config file contains "bad config"
916+
gitConfigPath := filepath.Join(dst, ".git", "config")
917+
configBytes, err := os.ReadFile(gitConfigPath)
918+
if err != nil {
919+
t.Fatalf(err.Error())
920+
}
921+
if strings.Contains(string(configBytes), "bad config") {
922+
t.Fatalf("The .git/config file contains 'bad config'")
923+
}
924+
}
925+
926+
func TestGitGetter_BadGitDirName(t *testing.T) {
927+
if !testHasGit {
928+
t.Log("git not found, skipping")
929+
t.Skip()
930+
}
931+
932+
ctx := context.Background()
933+
g := new(GitGetter)
934+
dst := tempDir(t)
935+
936+
url, err := url.Parse("https://github.com/hashicorp/go-getter")
937+
if err != nil {
938+
t.Fatal(err)
939+
}
940+
941+
_, err = os.Stat(dst)
942+
if err != nil && !os.IsNotExist(err) {
943+
t.Fatalf(err.Error())
944+
}
945+
if err == nil {
946+
// Remove all variations of .git directories
947+
err = removeCaseInsensitiveGitDirectory(dst)
948+
if err != nil {
949+
t.Fatalf(err.Error())
950+
}
951+
} else {
952+
// Clone a repository with a git directory
953+
err = g.clone(ctx, dst, testGitToken, url, "main", 1)
954+
if err != nil {
955+
t.Fatalf(err.Error())
956+
}
957+
958+
// Rename the .git directory to .GIT
959+
oldPath := filepath.Join(dst, ".git")
960+
newPath := filepath.Join(dst, ".GIT")
961+
err = os.Rename(oldPath, newPath)
962+
if err != nil {
963+
t.Fatalf(err.Error())
964+
}
965+
966+
// Remove all variations of .git directories
967+
err = removeCaseInsensitiveGitDirectory(dst)
968+
if err != nil {
969+
t.Fatalf(err.Error())
970+
}
971+
}
972+
if err != nil {
973+
t.Fatalf(err.Error())
974+
}
975+
976+
// Check if the .GIT directory exists
977+
if _, err := os.Stat(filepath.Join(dst, ".GIT")); !os.IsNotExist(err) {
978+
t.Fatalf(".GIT directory still exists")
979+
}
980+
981+
// Check if the .git directory exists
982+
if _, err := os.Stat(filepath.Join(dst, ".git")); !os.IsNotExist(err) {
983+
t.Fatalf(".git directory still exists")
984+
}
985+
}
986+
869987
// gitRepo is a helper struct which controls a single temp git repo.
870988
type gitRepo struct {
871989
t *testing.T

0 commit comments

Comments
 (0)