@@ -2,74 +2,186 @@ package envbuilder_test
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"io"
6
7
"net/http/httptest"
8
+ "net/url"
7
9
"os"
10
+ "regexp"
8
11
"testing"
9
12
"time"
10
13
11
14
"github.com/coder/envbuilder"
12
15
"github.com/coder/envbuilder/gittest"
16
+ "github.com/go-git/go-billy/v5"
13
17
"github.com/go-git/go-billy/v5/memfs"
14
18
"github.com/go-git/go-git/v5"
15
19
"github.com/go-git/go-git/v5/plumbing/object"
20
+ githttp "github.com/go-git/go-git/v5/plumbing/transport/http"
16
21
"github.com/stretchr/testify/require"
17
22
)
18
23
19
24
func TestCloneRepo (t * testing.T ) {
20
25
t .Parallel ()
21
26
22
- t .Run ("Clones" , func (t * testing.T ) {
23
- t .Parallel ()
27
+ for _ , tc := range []struct {
28
+ name string
29
+ srvUsername string
30
+ srvPassword string
31
+ username string
32
+ password string
33
+ mungeURL func (* string )
34
+ expectError string
35
+ expectClone bool
36
+ }{
37
+ {
38
+ name : "no auth" ,
39
+ expectClone : true ,
40
+ },
41
+ {
42
+ name : "auth" ,
43
+ srvUsername : "user" ,
44
+ srvPassword : "password" ,
45
+ username : "user" ,
46
+ password : "password" ,
47
+ expectClone : true ,
48
+ },
49
+ {
50
+ name : "auth but no creds" ,
51
+ srvUsername : "user" ,
52
+ srvPassword : "password" ,
53
+ expectClone : false ,
54
+ expectError : "authentication required" ,
55
+ },
56
+ {
57
+ name : "invalid auth" ,
58
+ srvUsername : "user" ,
59
+ srvPassword : "password" ,
60
+ username : "notuser" ,
61
+ password : "notpassword" ,
62
+ expectClone : false ,
63
+ expectError : "authentication required" ,
64
+ },
65
+ {
66
+ name : "tokenish username" ,
67
+ srvUsername : "tokentokentoken" ,
68
+ srvPassword : "" ,
69
+ username : "tokentokentoken" ,
70
+ password : "" ,
71
+ expectClone : true ,
72
+ },
73
+ } {
74
+ tc := tc
75
+ t .Run (tc .name , func (t * testing.T ) {
76
+ t .Parallel ()
24
77
25
- serverFS := memfs .New ()
26
- repo := gittest .NewRepo (t , serverFS )
27
- tree , err := repo .Worktree ()
28
- require .NoError (t , err )
78
+ // We do not overwrite a repo if one is already present.
79
+ t .Run ("AlreadyCloned" , func (t * testing.T ) {
80
+ srvURL := setupGit (t , tc .srvUsername , tc .srvPassword )
81
+ clientFS := memfs .New ()
82
+ // A repo already exists!
83
+ _ = gittest .NewRepo (t , clientFS )
84
+ cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
85
+ Path : "/" ,
86
+ RepoURL : srvURL ,
87
+ Storage : clientFS ,
88
+ })
89
+ require .NoError (t , err )
90
+ require .False (t , cloned )
91
+ })
29
92
30
- gittest .WriteFile (t , serverFS , "README.md" , "Hello, world!" )
31
- _ , err = tree .Add ("README.md" )
32
- require .NoError (t , err )
33
- commit , err := tree .Commit ("Wow!" , & git.CommitOptions {
34
- Author : & object.Signature {
35
- Name : "Example" ,
36
-
37
- When : time .Now (),
38
- },
39
- })
40
- require .NoError (t , err )
41
- _ , err = repo .CommitObject (commit )
42
- require .NoError (t , err )
93
+ // Basic Auth
94
+ t .Run ("BasicAuth" , func (t * testing.T ) {
95
+ t .Parallel ()
96
+ srvURL := setupGit (t , tc .srvUsername , tc .srvPassword )
97
+ clientFS := memfs .New ()
43
98
44
- srv := httptest .NewServer (gittest .NewServer (serverFS ))
99
+ cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
100
+ Path : "/workspace" ,
101
+ RepoURL : srvURL ,
102
+ Storage : clientFS ,
103
+ RepoAuth : & githttp.BasicAuth {
104
+ Username : tc .username ,
105
+ Password : tc .password ,
106
+ },
107
+ })
108
+ require .Equal (t , tc .expectClone , cloned )
109
+ if tc .expectError != "" {
110
+ require .ErrorContains (t , err , tc .expectError )
111
+ return
112
+ }
113
+ require .NoError (t , err )
114
+ require .True (t , cloned )
45
115
46
- clientFS := memfs .New ()
47
- cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
48
- Path : "/workspace" ,
49
- RepoURL : srv .URL ,
50
- Storage : clientFS ,
51
- })
52
- require .NoError (t , err )
53
- require .True (t , cloned )
116
+ readme := mustRead (t , clientFS , "/workspace/README.md" )
117
+ require .Equal (t , "Hello, world!" , readme )
118
+ gitConfig := mustRead (t , clientFS , "/workspace/.git/config" )
119
+ // Ensure we do not modify the git URL that folks pass in.
120
+ require .Regexp (t , fmt .Sprintf (`(?m)^\s+url\s+=\s+%s\s*$` , regexp .QuoteMeta (srvURL )), gitConfig )
121
+ })
54
122
55
- file , err := clientFS .OpenFile ("/workspace/README.md" , os .O_RDONLY , 0644 )
56
- require .NoError (t , err )
57
- defer file .Close ()
58
- content , err := io .ReadAll (file )
59
- require .NoError (t , err )
60
- require .Equal (t , "Hello, world!" , string (content ))
61
- })
123
+ // In-URL-style auth e.g. http://user:password@host:port
124
+ t .Run ("InURL" , func (t * testing.T ) {
125
+ t .Parallel ()
126
+ srvURL := setupGit (t , tc .srvUsername , tc .srvPassword )
127
+ authURL , err := url .Parse (srvURL )
128
+ require .NoError (t , err )
129
+ authURL .User = url .UserPassword (tc .username , tc .password )
130
+ clientFS := memfs .New ()
62
131
63
- t .Run ("DoesntCloneIfRepoExists" , func (t * testing.T ) {
64
- t .Parallel ()
65
- clientFS := memfs .New ()
66
- gittest .NewRepo (t , clientFS )
67
- cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
68
- Path : "/" ,
69
- RepoURL : "https://example.com" ,
70
- Storage : clientFS ,
132
+ cloned , err := envbuilder .CloneRepo (context .Background (), envbuilder.CloneRepoOptions {
133
+ Path : "/workspace" ,
134
+ RepoURL : authURL .String (),
135
+ Storage : clientFS ,
136
+ })
137
+ require .Equal (t , tc .expectClone , cloned )
138
+ if tc .expectError != "" {
139
+ require .ErrorContains (t , err , tc .expectError )
140
+ return
141
+ }
142
+ require .NoError (t , err )
143
+ require .True (t , cloned )
144
+
145
+ readme := mustRead (t , clientFS , "/workspace/README.md" )
146
+ require .Equal (t , "Hello, world!" , readme )
147
+ gitConfig := mustRead (t , clientFS , "/workspace/.git/config" )
148
+ // Ensure we do not modify the git URL that folks pass in.
149
+ require .Regexp (t , fmt .Sprintf (`(?m)^\s+url\s+=\s+%s\s*$` , regexp .QuoteMeta (authURL .String ())), gitConfig )
150
+ })
71
151
})
72
- require .NoError (t , err )
73
- require .False (t , cloned )
152
+ }
153
+ }
154
+
155
+ func mustRead (t * testing.T , fs billy.Filesystem , path string ) string {
156
+ t .Helper ()
157
+ f , err := fs .OpenFile (path , os .O_RDONLY , 0644 )
158
+ require .NoError (t , err )
159
+ content , err := io .ReadAll (f )
160
+ require .NoError (t , err )
161
+ return string (content )
162
+ }
163
+
164
+ func setupGit (t * testing.T , user , pass string ) (url string ) {
165
+ serverFS := memfs .New ()
166
+ repo := gittest .NewRepo (t , serverFS )
167
+ tree , err := repo .Worktree ()
168
+ require .NoError (t , err )
169
+
170
+ gittest .WriteFile (t , serverFS , "README.md" , "Hello, world!" )
171
+ _ , err = tree .Add ("README.md" )
172
+ require .NoError (t , err )
173
+ commit , err := tree .Commit ("Wow!" , & git.CommitOptions {
174
+ Author : & object.Signature {
175
+ Name : "Example" ,
176
+
177
+ When : time .Now (),
178
+ },
74
179
})
180
+ require .NoError (t , err )
181
+ _ , err = repo .CommitObject (commit )
182
+ require .NoError (t , err )
183
+
184
+ authMW := gittest .BasicAuthMW (user , pass )
185
+ srv := httptest .NewServer (authMW (gittest .NewServer (serverFS )))
186
+ return srv .URL
75
187
}
0 commit comments