Skip to content

Commit e7578c2

Browse files
committed
Fix support for getting single files from GitHub
This currently fails for GitHub (and possibly other Git repositories) because there is an assumption in the "client.go" file that the "subDir" segment is always a directory. However, for this URL: https://github.com/owner/repo/subdir/file.txt The "subDir" variable would actually be a file ("subdir/file.txt") and hence the client should use "copyFile" rather than "copyDir" when copying the "subDir" to the final destination. This change fixes that to check whether the "subDir" variable is a file or a directory, and appropriately uses "copyDir" or "copyFile". It also returns the single file in the "GetResult" object, if indeed a single file was requested. Tests attached.
1 parent 4e45866 commit e7578c2

File tree

2 files changed

+91
-4
lines changed

2 files changed

+91
-4
lines changed

client.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,22 @@ func (c *Client) get(ctx context.Context, req *Request, g Getter) (*GetResult, *
284284
return nil, &getError{true, err}
285285
}
286286

287-
err = copyDir(ctx, req.realDst, subDir, false, req.umask())
288-
if err != nil {
289-
return nil, &getError{false, err}
287+
if stat, err := os.Stat(subDir); err != nil {
288+
return nil, &getError{false, fmt.Errorf("failed to stat '%s': %w", subDir, err)}
289+
} else if stat.IsDir() {
290+
err = copyDir(ctx, req.realDst, subDir, false, req.umask())
291+
if err != nil {
292+
return nil, &getError{false, err}
293+
}
294+
return &GetResult{req.realDst}, nil
295+
} else {
296+
target := filepath.Join(req.realDst, filepath.Base(subDir))
297+
_, err = copyFile(ctx, target, subDir, 0755, req.umask())
298+
if err != nil {
299+
return nil, &getError{false, fmt.Errorf("failed to copy '%s' to '%s': %w", subDir, target, err)}
300+
}
301+
return &GetResult{target}, nil
290302
}
291-
return &GetResult{req.realDst}, nil
292303
}
293304

294305
return &GetResult{req.Dst}, nil

get_github_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package getter
2+
3+
import (
4+
"context"
5+
testing_helper "github.com/hashicorp/go-getter/v2/helper/testing"
6+
"os"
7+
"path/filepath"
8+
"testing"
9+
)
10+
11+
const basicMainTFExpectedContents = `# Hello
12+
13+
module "foo" {
14+
source = "./foo"
15+
}
16+
`
17+
18+
func TestGitGetter_githubDirWithModeAny(t *testing.T) {
19+
if !testHasGit {
20+
t.Skip("git not found, skipping")
21+
}
22+
23+
ctx := context.Background()
24+
dst := testing_helper.TempDir(t)
25+
defer os.RemoveAll(dst)
26+
27+
req := &Request{
28+
Src: "git::https://github.com/arikkfir/go-getter.git//testdata/basic?ref=v2",
29+
Dst: dst,
30+
GetMode: ModeAny,
31+
Copy: true,
32+
}
33+
client := Client{}
34+
result, err := client.Get(ctx, req)
35+
if err != nil {
36+
t.Fatalf("Failed fetching GitHub directory: %s", err)
37+
} else if stat, err := os.Stat(result.Dst); err != nil {
38+
t.Fatalf("Failed stat dst at '%s': %s", result.Dst, err)
39+
} else if !stat.IsDir() {
40+
t.Fatalf("Expected '%s' to be a directory", result.Dst)
41+
} else if entries, err := os.ReadDir(result.Dst); err != nil {
42+
t.Fatalf("Failed listing directory '%s': %s", result.Dst, err)
43+
} else if len(entries) != 3 {
44+
t.Fatalf("Expected dir '%s' to contain 3 items: %s", result.Dst, err)
45+
} else {
46+
testing_helper.AssertContents(t, filepath.Join(result.Dst, "main.tf"), basicMainTFExpectedContents)
47+
}
48+
}
49+
50+
func TestGitGetter_githubFileWithModeAny(t *testing.T) {
51+
if !testHasGit {
52+
t.Skip("git not found, skipping")
53+
}
54+
55+
ctx := context.Background()
56+
dst := testing_helper.TempDir(t)
57+
defer os.RemoveAll(dst)
58+
59+
req := &Request{
60+
Src: "git::https://github.com/arikkfir/go-getter.git//testdata/basic/main.tf?ref=v2",
61+
Dst: dst,
62+
GetMode: ModeAny,
63+
Copy: true,
64+
}
65+
client := Client{}
66+
result, err := client.Get(ctx, req)
67+
if err != nil {
68+
t.Fatalf("Failed fetching GitHub file: %s", err)
69+
} else if stat, err := os.Stat(result.Dst); err != nil {
70+
t.Fatalf("Failed stat dst at '%s': %s", result.Dst, err)
71+
} else if stat.IsDir() {
72+
t.Fatalf("Expected '%s' to be a file", result.Dst)
73+
} else {
74+
testing_helper.AssertContents(t, result.Dst, basicMainTFExpectedContents)
75+
}
76+
}

0 commit comments

Comments
 (0)