1
2
3
4 package git
5
6 import (
7 "fmt"
8 "path/filepath"
9 "testing"
10 "time"
11
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
14 )
15
16 func TestNewRepoSpecFromUrl_Permute(t *testing.T) {
17
18
19
20
21 var schemeAuthority = []struct{ raw, normalized string }{
22 {"gitHub.com/", "https://github.com/"},
23 {"github.com:", "https://github.com/"},
24 {"http://github.com/", "https://github.com/"},
25 {"https://github.com/", "https://github.com/"},
26 {"hTTps://github.com/", "https://github.com/"},
27 {"https://git-codecommit.us-east-2.amazonaws.com/", "https://git-codecommit.us-east-2.amazonaws.com/"},
28 {"https://fabrikops2.visualstudio.com/", "https://fabrikops2.visualstudio.com/"},
29 {"ssh://git.example.com:7999/", "ssh://git.example.com:7999/"},
30 {"git::https://gitlab.com/", "https://gitlab.com/"},
31 {"git::http://git.example.com/", "http://git.example.com/"},
32 {"git::https://git.example.com/", "https://git.example.com/"},
33 {"git@github.com:", "git@github.com:"},
34 {"git@github.com/", "git@github.com:"},
35 {"git::git@github.com:", "git@github.com:"},
36 {"org-12345@github.com:", "org-12345@github.com:"},
37 {"org-12345@github.com/", "org-12345@github.com:"},
38 }
39 var repoPaths = []string{"someOrg/someRepo", "kubernetes/website"}
40 var pathNames = []string{"README.md", "foo/krusty.txt", ""}
41 var refArgs = []string{"group/version", "someBranch", "master", "v0.1.0", ""}
42
43 makeURL := func(hostFmt, repoPath, path, ref string) string {
44 if len(path) > 0 {
45 repoPath = filepath.Join(repoPath, path)
46 }
47 url := hostFmt + repoPath
48 if ref != "" {
49 url += refQuery + ref
50 }
51 return url
52 }
53
54 var i int
55 for _, v := range schemeAuthority {
56 hostRaw := v.raw
57 hostSpec := v.normalized
58 for _, repoPath := range repoPaths {
59 for _, pathName := range pathNames {
60 for _, hrefArg := range refArgs {
61 t.Run(fmt.Sprintf("t%d", i), func(t *testing.T) {
62 uri := makeURL(hostRaw, repoPath, pathName, hrefArg)
63 rs, err := NewRepoSpecFromURL(uri)
64 require.NoErrorf(t, err, "unexpected error creating RepoSpec for uri %s", uri)
65 assert.Equal(t, hostSpec, rs.Host, "unexpected host for uri %s", uri)
66 assert.Equal(t, repoPath, rs.RepoPath, "unexpected RepoPath for uri %s", uri)
67 assert.Equal(t, pathName, rs.KustRootPath, "unexpected KustRootPath for uri %s", uri)
68 assert.Equal(t, hrefArg, rs.Ref, "unexpected ref for uri %s", uri)
69 })
70 i++
71 }
72 }
73 }
74 }
75 }
76
77 func TestNewRepoSpecFromUrlErrors(t *testing.T) {
78 badData := map[string]struct {
79 url, error string
80 }{
81 "absolute_path": {
82 "/tmp",
83 "uri looks like abs path",
84 },
85 "relative path": {
86 "../../tmp",
87 "failed to parse scheme",
88 },
89 "local path that looks somewhat like a github url": {
90 "src/github.com/org/repo/path",
91 "failed to parse scheme",
92 },
93 "no_slashes": {
94 "iauhsdiuashduas",
95 "failed to parse scheme",
96 },
97 "bad_scheme": {
98 "htxxxtp://github.com/",
99 "failed to parse scheme",
100 },
101 "no_org_repo": {
102 "ssh://git.example.com",
103 "failed to parse repo path segment",
104 },
105 "hashicorp_git_only": {
106 "git::___",
107 "failed to parse scheme",
108 },
109 "query_after_host": {
110 "https://host?ref=group/version/minor_version",
111 "failed to parse repo path segment",
112 },
113 "path_exits_repo": {
114 "https://github.com/org/repo.git//path/../../exits/repo",
115 "url path exits repo",
116 },
117 "bad github separator": {
118 "github.com!org/repo.git//path",
119 "failed to parse scheme",
120 },
121 "mysterious gh: prefix previously supported is no longer handled": {
122 "gh:org/repo",
123 "failed to parse scheme",
124 },
125 "invalid Github url missing orgrepo": {
126 "https://github.com/thisisa404.yaml",
127 "failed to parse repo path segment",
128 },
129 "file protocol with excessive slashes": {
130 "file:////tmp//path/to/whatever",
131 "failed to parse repo path segment",
132 },
133 "unsupported protocol after username (invalid)": {
134 "git@scp://github.com/org/repo.git//path",
135 "failed to parse repo path segment",
136 },
137 "supported protocol after username (invalid)": {
138 "git@ssh://github.com/org/repo.git//path",
139 "failed to parse repo path segment",
140 },
141 }
142
143 for name, testCase := range badData {
144 t.Run(name, func(t *testing.T) {
145 _, err := NewRepoSpecFromURL(testCase.url)
146 require.Error(t, err)
147 require.Contains(t, err.Error(), testCase.error)
148 })
149 }
150 }
151
152 func TestNewRepoSpecFromUrl_Smoke(t *testing.T) {
153
154
155
156 testcases := []struct {
157 name string
158 input string
159 repoSpec RepoSpec
160 cloneSpec string
161 absPath string
162 }{
163 {
164 name: "https aws code commit url",
165 input: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo/somedir",
166 cloneSpec: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo",
167 absPath: notCloned.Join("somedir"),
168 repoSpec: RepoSpec{
169 Host: "https://git-codecommit.us-east-2.amazonaws.com/",
170 RepoPath: "someorg/somerepo",
171 KustRootPath: "somedir",
172 },
173 },
174 {
175 name: "https aws code commit url with params",
176 input: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo/somedir?ref=testbranch",
177 cloneSpec: "https://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo",
178 absPath: notCloned.Join("somedir"),
179 repoSpec: RepoSpec{
180 Host: "https://git-codecommit.us-east-2.amazonaws.com/",
181 RepoPath: "someorg/somerepo",
182 KustRootPath: "somedir",
183 Ref: "testbranch",
184 },
185 },
186 {
187 name: "legacy azure https url with params",
188 input: "https://fabrikops2.visualstudio.com/someorg/somerepo?ref=master",
189 cloneSpec: "https://fabrikops2.visualstudio.com/someorg/somerepo",
190 absPath: notCloned.String(),
191 repoSpec: RepoSpec{
192 Host: "https://fabrikops2.visualstudio.com/",
193 RepoPath: "someorg/somerepo",
194 Ref: "master",
195 },
196 },
197 {
198 name: "http github url without git suffix",
199 input: "http://github.com/someorg/somerepo/somedir",
200 cloneSpec: "https://github.com/someorg/somerepo",
201 absPath: notCloned.Join("somedir"),
202 repoSpec: RepoSpec{
203 Host: "https://github.com/",
204 RepoPath: "someorg/somerepo",
205 KustRootPath: "somedir",
206 },
207 },
208 {
209 name: "scp github url without git suffix",
210 input: "git@github.com:someorg/somerepo/somedir",
211 cloneSpec: "git@github.com:someorg/somerepo",
212 absPath: notCloned.Join("somedir"),
213 repoSpec: RepoSpec{
214 Host: "git@github.com:",
215 RepoPath: "someorg/somerepo",
216 KustRootPath: "somedir",
217 },
218 },
219 {
220 name: "http github url with git suffix",
221 input: "http://github.com/someorg/somerepo.git/somedir",
222 cloneSpec: "https://github.com/someorg/somerepo.git",
223 absPath: notCloned.Join("somedir"),
224 repoSpec: RepoSpec{
225 Host: "https://github.com/",
226 RepoPath: "someorg/somerepo.git",
227 KustRootPath: "somedir",
228 },
229 },
230 {
231 name: "scp github url with git suffix",
232 input: "git@github.com:someorg/somerepo.git/somedir",
233 cloneSpec: "git@github.com:someorg/somerepo.git",
234 absPath: notCloned.Join("somedir"),
235 repoSpec: RepoSpec{
236 Host: "git@github.com:",
237 RepoPath: "someorg/somerepo.git",
238 KustRootPath: "somedir",
239 },
240 },
241 {
242 name: "non-github_scp",
243 input: "git@gitlab2.sqtools.ru:infra/kubernetes/thanos-base.git?ref=v0.1.0",
244 cloneSpec: "git@gitlab2.sqtools.ru:infra/kubernetes/thanos-base.git",
245 absPath: notCloned.String(),
246 repoSpec: RepoSpec{
247 Host: "git@gitlab2.sqtools.ru:",
248 RepoPath: "infra/kubernetes/thanos-base.git",
249 Ref: "v0.1.0",
250 },
251 },
252 {
253 name: "non-github_scp with path delimiter",
254 input: "git@bitbucket.org:company/project.git//path?ref=branch",
255 cloneSpec: "git@bitbucket.org:company/project.git",
256 absPath: notCloned.Join("path"),
257 repoSpec: RepoSpec{
258 Host: "git@bitbucket.org:",
259 RepoPath: "company/project.git",
260 KustRootPath: "path",
261 Ref: "branch",
262 },
263 },
264 {
265 name: "non-github_scp incorrectly using slash (invalid but currently passed through to git)",
266 input: "git@bitbucket.org/company/project.git//path?ref=branch",
267 cloneSpec: "git@bitbucket.org/company/project.git",
268 absPath: notCloned.Join("path"),
269 repoSpec: RepoSpec{
270 Host: "git@bitbucket.org/",
271 RepoPath: "company/project.git",
272 KustRootPath: "path",
273 Ref: "branch",
274 },
275 },
276 {
277 name: "non-github_git-user_ssh",
278 input: "ssh://git@bitbucket.org/company/project.git//path?ref=branch",
279 cloneSpec: "ssh://git@bitbucket.org/company/project.git",
280 absPath: notCloned.Join("path"),
281 repoSpec: RepoSpec{
282 Host: "ssh://git@bitbucket.org/",
283 RepoPath: "company/project.git",
284 KustRootPath: "path",
285 Ref: "branch",
286 },
287 },
288 {
289 name: "_git host delimiter in non-github url",
290 input: "https://itfs.mycompany.com/collection/project/_git/somerepos",
291 cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
292 absPath: notCloned.String(),
293 repoSpec: RepoSpec{
294 Host: "https://itfs.mycompany.com/",
295 RepoPath: "collection/project/_git/somerepos",
296 },
297 },
298 {
299 name: "_git host delimiter in non-github url with params",
300 input: "https://itfs.mycompany.com/collection/project/_git/somerepos?version=v1.0.0",
301 cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
302 absPath: notCloned.String(),
303 repoSpec: RepoSpec{
304 Host: "https://itfs.mycompany.com/",
305 RepoPath: "collection/project/_git/somerepos",
306 Ref: "v1.0.0",
307 },
308 },
309 {
310 name: "_git host delimiter in non-github url with kust root path and params",
311 input: "https://itfs.mycompany.com/collection/project/_git/somerepos/somedir?version=v1.0.0",
312 cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
313 absPath: notCloned.Join("somedir"),
314 repoSpec: RepoSpec{
315 Host: "https://itfs.mycompany.com/",
316 RepoPath: "collection/project/_git/somerepos",
317 KustRootPath: "somedir",
318 Ref: "v1.0.0",
319 },
320 },
321 {
322 name: "_git host delimiter in non-github url with no kust root path",
323 input: "git::https://itfs.mycompany.com/collection/project/_git/somerepos",
324 cloneSpec: "https://itfs.mycompany.com/collection/project/_git/somerepos",
325 absPath: notCloned.String(),
326 repoSpec: RepoSpec{
327 Host: "https://itfs.mycompany.com/",
328 RepoPath: "collection/project/_git/somerepos",
329 },
330 },
331 {
332 name: "https bitbucket url with git suffix",
333 input: "https://bitbucket.example.com/scm/project/repository.git",
334 cloneSpec: "https://bitbucket.example.com/scm/project/repository.git",
335 absPath: notCloned.String(),
336 repoSpec: RepoSpec{
337 Host: "https://bitbucket.example.com/",
338 RepoPath: "scm/project/repository.git",
339 },
340 },
341 {
342 name: "ssh aws code commit url",
343 input: "ssh://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo/somepath",
344 cloneSpec: "ssh://git-codecommit.us-east-2.amazonaws.com/someorg/somerepo",
345 absPath: notCloned.Join("somepath"),
346 repoSpec: RepoSpec{
347 Host: "ssh://git-codecommit.us-east-2.amazonaws.com/",
348 RepoPath: "someorg/somerepo",
349 KustRootPath: "somepath",
350 },
351 },
352 {
353 name: "scp Github with slash fixed to colon",
354 input: "git@github.com/someorg/somerepo/somepath",
355 cloneSpec: "git@github.com:someorg/somerepo",
356 absPath: notCloned.Join("somepath"),
357 repoSpec: RepoSpec{
358 Host: "git@github.com:",
359 RepoPath: "someorg/somerepo",
360 KustRootPath: "somepath",
361 },
362 },
363 {
364 name: "https Github with double slash path delimiter and params",
365 input: "https://github.com/kubernetes-sigs/kustomize//examples/multibases/dev/?ref=v1.0.6",
366 cloneSpec: "https://github.com/kubernetes-sigs/kustomize",
367 absPath: notCloned.Join("/examples/multibases/dev"),
368 repoSpec: RepoSpec{
369 Host: "https://github.com/",
370 RepoPath: "kubernetes-sigs/kustomize",
371 KustRootPath: "examples/multibases/dev/",
372 Ref: "v1.0.6",
373 },
374 },
375 {
376 name: "file protocol with git-suffixed repo path and params",
377 input: "file://a/b/c/someRepo.git/somepath?ref=someBranch",
378 cloneSpec: "file://a/b/c/someRepo.git",
379 absPath: notCloned.Join("somepath"),
380 repoSpec: RepoSpec{
381 Host: "file://",
382 RepoPath: "a/b/c/someRepo.git",
383 KustRootPath: "somepath",
384 Ref: "someBranch",
385 },
386 },
387 {
388 name: "file protocol with two slashes, with kust root path and params",
389 input: "file://a/b/c/someRepo//somepath?ref=someBranch",
390 cloneSpec: "file://a/b/c/someRepo",
391 absPath: notCloned.Join("somepath"),
392 repoSpec: RepoSpec{
393 Host: "file://",
394 RepoPath: "a/b/c/someRepo",
395 KustRootPath: "somepath",
396 Ref: "someBranch",
397 },
398 },
399 {
400 name: "file protocol with two slashes, with ref and no kust root path",
401 input: "file://a/b/c/someRepo?ref=someBranch",
402 cloneSpec: "file://a/b/c/someRepo",
403 absPath: notCloned.String(),
404 repoSpec: RepoSpec{
405 Host: "file://",
406 RepoPath: "a/b/c/someRepo",
407 Ref: "someBranch",
408 },
409 },
410 {
411 name: "file protocol with three slashes, with ref and no kust root path",
412 input: "file:///a/b/c/someRepo?ref=someBranch",
413 cloneSpec: "file:///a/b/c/someRepo",
414 absPath: notCloned.String(),
415 repoSpec: RepoSpec{
416 Host: "file://",
417 RepoPath: "/a/b/c/someRepo",
418 Ref: "someBranch",
419 },
420 },
421 {
422 name: "ssh Github with double-slashed path delimiter and params",
423 input: "ssh://git@github.com/kubernetes-sigs/kustomize//examples/multibases/dev?ref=v1.0.6",
424 cloneSpec: "git@github.com:kubernetes-sigs/kustomize",
425 absPath: notCloned.Join("examples/multibases/dev"),
426 repoSpec: RepoSpec{
427 Host: "git@github.com:",
428 RepoPath: "kubernetes-sigs/kustomize",
429 KustRootPath: "examples/multibases/dev",
430 Ref: "v1.0.6",
431 },
432 },
433 {
434 name: "file protocol with three slashes, no kust root path or params",
435 input: "file:///a/b/c/someRepo",
436 cloneSpec: "file:///a/b/c/someRepo",
437 absPath: notCloned.String(),
438 repoSpec: RepoSpec{
439 Host: "file://",
440 RepoPath: "/a/b/c/someRepo",
441 },
442 },
443 {
444 name: "file protocol with three slashes, no repo or kust root path or params",
445 input: "file:///",
446 cloneSpec: "file:///",
447 absPath: notCloned.String(),
448 repoSpec: RepoSpec{
449 Host: "file://",
450 RepoPath: "/",
451 },
452 },
453 {
454 name: "arbitrary https host with double-slash path delimiter",
455 input: "https://example.org/path/to/repo//examples/multibases/dev",
456 cloneSpec: "https://example.org/path/to/repo",
457 absPath: notCloned.Join("/examples/multibases/dev"),
458 repoSpec: RepoSpec{
459 Host: "https://example.org/",
460 RepoPath: "path/to/repo",
461 KustRootPath: "examples/multibases/dev",
462 },
463 },
464 {
465 name: "arbitrary https host with .git repo suffix",
466 input: "https://example.org/path/to/repo.git/examples/multibases/dev",
467 cloneSpec: "https://example.org/path/to/repo.git",
468 absPath: notCloned.Join("/examples/multibases/dev"),
469 repoSpec: RepoSpec{
470 Host: "https://example.org/",
471 RepoPath: "path/to/repo.git",
472 KustRootPath: "examples/multibases/dev",
473 },
474 },
475 {
476 name: "arbitrary ssh host with double-slash path delimiter",
477 input: "ssh://alice@example.com/path/to/repo//examples/multibases/dev",
478 cloneSpec: "ssh://alice@example.com/path/to/repo",
479 absPath: notCloned.Join("/examples/multibases/dev"),
480 repoSpec: RepoSpec{
481 Host: "ssh://alice@example.com/",
482 RepoPath: "path/to/repo",
483 KustRootPath: "examples/multibases/dev",
484 },
485 },
486 {
487 name: "query_slash",
488 input: "https://authority/org/repo?ref=group/version",
489 cloneSpec: "https://authority/org/repo",
490 absPath: notCloned.String(),
491 repoSpec: RepoSpec{
492 Host: "https://authority/",
493 RepoPath: "org/repo",
494 Ref: "group/version",
495 },
496 },
497 {
498 name: "query_git_delimiter",
499 input: "https://authority/org/repo/?ref=includes_git/for_some_reason",
500 cloneSpec: "https://authority/org/repo",
501 absPath: notCloned.String(),
502 repoSpec: RepoSpec{
503 Host: "https://authority/",
504 RepoPath: "org/repo",
505 Ref: "includes_git/for_some_reason",
506 },
507 },
508 {
509 name: "query_git_suffix",
510 input: "https://authority/org/repo/?ref=includes.git/for_some_reason",
511 cloneSpec: "https://authority/org/repo",
512 absPath: notCloned.String(),
513 repoSpec: RepoSpec{
514 Host: "https://authority/",
515 RepoPath: "org/repo",
516 Ref: "includes.git/for_some_reason",
517 },
518 },
519 {
520 name: "non_parsable_path",
521 input: "https://authority/org/repo/%-invalid-uri-so-not-parsable-by-net/url.Parse",
522 cloneSpec: "https://authority/org/repo",
523 absPath: notCloned.Join("%-invalid-uri-so-not-parsable-by-net/url.Parse"),
524 repoSpec: RepoSpec{
525 Host: "https://authority/",
526 RepoPath: "org/repo",
527 KustRootPath: "%-invalid-uri-so-not-parsable-by-net/url.Parse",
528 },
529 },
530 {
531 name: "non-git username with non-github host",
532 input: "ssh://myusername@bitbucket.org/ourteamname/ourrepositoryname.git//path?ref=branch",
533 cloneSpec: "ssh://myusername@bitbucket.org/ourteamname/ourrepositoryname.git",
534 absPath: notCloned.Join("path"),
535 repoSpec: RepoSpec{
536 Host: "ssh://myusername@bitbucket.org/",
537 RepoPath: "ourteamname/ourrepositoryname.git",
538 KustRootPath: "path",
539 Ref: "branch",
540 },
541 },
542 {
543 name: "username-like filepath with file protocol",
544 input: "file://git@home/path/to/repository.git//path?ref=branch",
545 cloneSpec: "file://git@home/path/to/repository.git",
546 absPath: notCloned.Join("path"),
547 repoSpec: RepoSpec{
548 Host: "file://",
549 RepoPath: "git@home/path/to/repository.git",
550 KustRootPath: "path",
551 Ref: "branch",
552 },
553 },
554 {
555 name: "username with http protocol (invalid but currently passed through to git)",
556 input: "http://git@home.com/path/to/repository.git//path?ref=branch",
557 cloneSpec: "http://git@home.com/path/to/repository.git",
558 absPath: notCloned.Join("path"),
559 repoSpec: RepoSpec{
560 Host: "http://git@home.com/",
561 RepoPath: "path/to/repository.git",
562 KustRootPath: "path",
563 Ref: "branch",
564 },
565 },
566 {
567 name: "username with https protocol (invalid but currently passed through to git)",
568 input: "https://git@home.com/path/to/repository.git//path?ref=branch",
569 cloneSpec: "https://git@home.com/path/to/repository.git",
570 absPath: notCloned.Join("path"),
571 repoSpec: RepoSpec{
572 Host: "https://git@home.com/",
573 RepoPath: "path/to/repository.git",
574 KustRootPath: "path",
575 Ref: "branch",
576 },
577 },
578 {
579 name: "complex github ssh url from docs",
580 input: "ssh://git@ssh.github.com:443/YOUR-USERNAME/YOUR-REPOSITORY.git",
581 cloneSpec: "ssh://git@ssh.github.com:443/YOUR-USERNAME/YOUR-REPOSITORY.git",
582 absPath: notCloned.String(),
583 repoSpec: RepoSpec{
584 Host: "ssh://git@ssh.github.com:443/",
585 RepoPath: "YOUR-USERNAME/YOUR-REPOSITORY.git",
586 KustRootPath: "",
587 },
588 },
589 {
590 name: "colon behind slash not scp delimiter",
591 input: "git@gitlab.com/user:name/YOUR-REPOSITORY.git/path",
592 cloneSpec: "git@gitlab.com/user:name/YOUR-REPOSITORY.git",
593 absPath: notCloned.Join("path"),
594 repoSpec: RepoSpec{
595 Host: "git@gitlab.com/",
596 RepoPath: "user:name/YOUR-REPOSITORY.git",
597 KustRootPath: "path",
598 },
599 },
600 {
601 name: "gitlab URLs with explicit git suffix",
602 input: "git@gitlab.com:gitlab-tests/sample-project.git",
603 cloneSpec: "git@gitlab.com:gitlab-tests/sample-project.git",
604 absPath: notCloned.String(),
605 repoSpec: RepoSpec{
606 Host: "git@gitlab.com:",
607 RepoPath: "gitlab-tests/sample-project.git",
608 },
609 },
610 {
611 name: "gitlab URLs without explicit git suffix",
612 input: "git@gitlab.com:gitlab-tests/sample-project",
613 cloneSpec: "git@gitlab.com:gitlab-tests/sample-project",
614 absPath: notCloned.String(),
615 repoSpec: RepoSpec{
616 Host: "git@gitlab.com:",
617 RepoPath: "gitlab-tests/sample-project",
618 },
619 },
620 {
621 name: "azure host with _git and // path separator",
622 input: "https://username@dev.azure.com/org/project/_git/repo//path/to/kustomization/root",
623 cloneSpec: "https://username@dev.azure.com/org/project/_git/repo",
624 absPath: notCloned.Join("path/to/kustomization/root"),
625 repoSpec: RepoSpec{
626 Host: "https://username@dev.azure.com/",
627 RepoPath: "org/project/_git/repo",
628 KustRootPath: "path/to/kustomization/root",
629 },
630 },
631 {
632 name: "legacy format azure host with _git",
633 input: "https://org.visualstudio.com/project/_git/repo/path/to/kustomization/root",
634 cloneSpec: "https://org.visualstudio.com/project/_git/repo",
635 absPath: notCloned.Join("path/to/kustomization/root"),
636 repoSpec: RepoSpec{
637 Host: "https://org.visualstudio.com/",
638 RepoPath: "project/_git/repo",
639 KustRootPath: "path/to/kustomization/root",
640 },
641 },
642 {
643 name: "ssh on github with custom username for custom ssh certificate authority",
644 input: "ssh://org-12345@github.com/kubernetes-sigs/kustomize",
645 cloneSpec: "org-12345@github.com:kubernetes-sigs/kustomize",
646 absPath: notCloned.String(),
647 repoSpec: RepoSpec{
648 Host: "org-12345@github.com:",
649 RepoPath: "kubernetes-sigs/kustomize",
650 },
651 },
652 {
653 name: "scp on github with custom username for custom ssh certificate authority",
654 input: "org-12345@github.com/kubernetes-sigs/kustomize",
655 cloneSpec: "org-12345@github.com:kubernetes-sigs/kustomize",
656 absPath: notCloned.String(),
657 repoSpec: RepoSpec{
658 Host: "org-12345@github.com:",
659 RepoPath: "kubernetes-sigs/kustomize",
660 },
661 },
662 {
663 name: "scp format gist url",
664 input: "git@gist.github.com:bc7947cb727d7f9217e7862d961a1ffd.git",
665 cloneSpec: "git@gist.github.com:bc7947cb727d7f9217e7862d961a1ffd.git",
666 absPath: notCloned.String(),
667 repoSpec: RepoSpec{
668 Host: "git@gist.github.com:",
669 RepoPath: "bc7947cb727d7f9217e7862d961a1ffd.git",
670 },
671 },
672 {
673 name: "https gist url",
674 input: "https://gist.github.com/bc7947cb727d7f9217e7862d961a1ffd.git",
675 cloneSpec: "https://gist.github.com/bc7947cb727d7f9217e7862d961a1ffd.git",
676 absPath: notCloned.String(),
677 repoSpec: RepoSpec{
678 Host: "https://gist.github.com/",
679 RepoPath: "bc7947cb727d7f9217e7862d961a1ffd.git",
680 },
681 },
682 }
683 for _, tc := range testcases {
684 t.Run(tc.name, func(t *testing.T) {
685 rs, err := NewRepoSpecFromURL(tc.input)
686 require.NoError(t, err)
687 assert.Equal(t, tc.cloneSpec, rs.CloneSpec(), "cloneSpec mismatch")
688 assert.Equal(t, tc.absPath, rs.AbsPath(), "absPath mismatch")
689
690
691
692 rs.raw = ""
693 rs.Dir = ""
694 rs.Submodules = false
695 rs.Timeout = 0
696 assert.Equal(t, &tc.repoSpec, rs)
697 })
698 }
699 }
700
701 func TestNewRepoSpecFromURL_DefaultQueryParams(t *testing.T) {
702 repoSpec, err := NewRepoSpecFromURL("https://github.com/org/repo")
703 require.NoError(t, err)
704 require.Equal(t, defaultSubmodules, repoSpec.Submodules)
705 require.Equal(t, defaultTimeout, repoSpec.Timeout)
706 }
707
708 func TestParseQuery(t *testing.T) {
709 testcases := []struct {
710 name string
711 input string
712 ref string
713 submodules bool
714 timeout time.Duration
715 }{
716 {
717 name: "empty",
718 input: "",
719 ref: "",
720 submodules: defaultSubmodules,
721 timeout: defaultTimeout,
722 },
723 {
724 name: "ref",
725 input: "ref=v1.0.0",
726 ref: "v1.0.0",
727 submodules: defaultSubmodules,
728 timeout: defaultTimeout,
729 },
730 {
731 name: "ref_slash",
732 input: "ref=kustomize/v4.5.7",
733 ref: "kustomize/v4.5.7",
734 submodules: defaultSubmodules,
735 timeout: defaultTimeout,
736 },
737 {
738 name: "version",
739 input: "version=master",
740 ref: "master",
741 submodules: defaultSubmodules,
742 timeout: defaultTimeout,
743 },
744 {
745 name: "ref_and_version",
746
747 input: "version=master&ref=v1.0.0",
748 ref: "v1.0.0",
749 submodules: defaultSubmodules,
750 timeout: defaultTimeout,
751 },
752 {
753 name: "empty_submodules",
754
755 input: "version=master&submodules=",
756 ref: "master",
757 submodules: defaultSubmodules,
758 timeout: defaultTimeout,
759 },
760 {
761 name: "bad_submodules",
762
763 input: "version=master&submodules=maybe",
764 ref: "master",
765 submodules: defaultSubmodules,
766 timeout: defaultTimeout,
767 },
768 {
769 name: "submodules_true",
770 input: "version=master&submodules=true",
771 ref: "master",
772 submodules: true,
773 timeout: defaultTimeout,
774 },
775 {
776 name: "submodules_false",
777 input: "version=master&submodules=false",
778 ref: "master",
779 submodules: false,
780 timeout: defaultTimeout,
781 },
782 {
783 name: "empty_timeout",
784
785 input: "version=master&timeout=",
786 ref: "master",
787 submodules: defaultSubmodules,
788 timeout: defaultTimeout,
789 },
790 {
791 name: "bad_timeout",
792
793 input: "version=master&timeout=jiffy",
794 ref: "master",
795 submodules: defaultSubmodules,
796 timeout: defaultTimeout,
797 },
798 {
799 name: "zero_timeout",
800
801 input: "version=master&timeout=0",
802 ref: "master",
803 submodules: defaultSubmodules,
804 timeout: defaultTimeout,
805 },
806 {
807 name: "zero_unit_timeout",
808 input: "version=master&timeout=0s",
809 ref: "master",
810 submodules: defaultSubmodules,
811 timeout: defaultTimeout,
812 },
813 {
814 name: "timeout",
815 input: "version=master&timeout=61",
816 ref: "master",
817 submodules: defaultSubmodules,
818 timeout: 61 * time.Second,
819 },
820 {
821 name: "timeout_unit",
822 input: "version=master&timeout=1m1s",
823 ref: "master",
824 submodules: defaultSubmodules,
825 timeout: 61 * time.Second,
826 },
827 {
828 name: "all",
829 input: "version=master&submodules=false&timeout=1m1s",
830 ref: "master",
831 submodules: false,
832 timeout: 61 * time.Second,
833 },
834 }
835 for _, tc := range testcases {
836 t.Run(tc.name, func(t *testing.T) {
837 ref, timeout, submodules := parseQuery(tc.input)
838 assert.Equal(t, tc.ref, ref, "ref mismatch")
839 assert.Equal(t, tc.timeout, timeout, "timeout mismatch")
840 assert.Equal(t, tc.submodules, submodules, "submodules mismatch")
841 })
842 }
843 }
844
View as plain text