github.com/argoproj/argo-cd/v3@v3.2.1/util/git/git_test.go (about) 1 package git 2 3 import ( 4 "io" 5 "net/http" 6 "os" 7 "path/filepath" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 "github.com/argoproj/argo-cd/v3/common" 14 "github.com/argoproj/argo-cd/v3/test/fixture/log" 15 "github.com/argoproj/argo-cd/v3/test/fixture/path" 16 "github.com/argoproj/argo-cd/v3/test/fixture/test" 17 ) 18 19 func TestIsCommitSHA(t *testing.T) { 20 assert.True(t, IsCommitSHA("9d921f65f3c5373b682e2eb4b37afba6592e8f8b")) 21 assert.True(t, IsCommitSHA("9D921F65F3C5373B682E2EB4B37AFBA6592E8F8B")) 22 assert.False(t, IsCommitSHA("gd921f65f3c5373b682e2eb4b37afba6592e8f8b")) 23 assert.False(t, IsCommitSHA("master")) 24 assert.False(t, IsCommitSHA("HEAD")) 25 assert.False(t, IsCommitSHA("9d921f6")) // only consider 40 characters hex strings as a commit-sha 26 assert.True(t, IsTruncatedCommitSHA("9d921f6")) 27 assert.False(t, IsTruncatedCommitSHA("9d921f")) // we only consider 7+ characters 28 assert.False(t, IsTruncatedCommitSHA("branch-name")) 29 } 30 31 func TestEnsurePrefix(t *testing.T) { 32 data := [][]string{ 33 {"world", "hello", "helloworld"}, 34 {"helloworld", "hello", "helloworld"}, 35 {"example.com", "https://", "https://example.com"}, 36 {"https://example.com", "https://", "https://example.com"}, 37 {"cd", "argo", "argocd"}, 38 {"argocd", "argo", "argocd"}, 39 {"", "argocd", "argocd"}, 40 {"argocd", "", "argocd"}, 41 } 42 for _, table := range data { 43 result := ensurePrefix(table[0], table[1]) 44 assert.Equal(t, table[2], result) 45 } 46 } 47 48 func TestIsSSHURL(t *testing.T) { 49 data := map[string]bool{ 50 "git://github.com/argoproj/test.git": false, 51 "git@GITHUB.com:argoproj/test.git": true, 52 "git@github.com:test": true, 53 "git@github.com:test.git": true, 54 "https://github.com/argoproj/test": false, 55 "https://github.com/argoproj/test.git": false, 56 "ssh://git@GITHUB.com:argoproj/test": true, 57 "ssh://git@GITHUB.com:argoproj/test.git": true, 58 "ssh://git@github.com:test.git": true, 59 } 60 for k, v := range data { 61 isSSH, _ := IsSSHURL(k) 62 assert.Equal(t, v, isSSH) 63 } 64 } 65 66 func TestIsSSHURLUserName(t *testing.T) { 67 isSSH, user := IsSSHURL("ssh://john@john-server.org:29418/project") 68 assert.True(t, isSSH) 69 assert.Equal(t, "john", user) 70 71 isSSH, user = IsSSHURL("john@john-server.org:29418/project") 72 assert.True(t, isSSH) 73 assert.Equal(t, "john", user) 74 75 isSSH, user = IsSSHURL("john@doe.org@john-server.org:29418/project") 76 assert.True(t, isSSH) 77 assert.Equal(t, "john@doe.org", user) 78 79 isSSH, user = IsSSHURL("ssh://john@doe.org@john-server.org:29418/project") 80 assert.True(t, isSSH) 81 assert.Equal(t, "john@doe.org", user) 82 83 isSSH, user = IsSSHURL("john@doe.org@john-server.org:project") 84 assert.True(t, isSSH) 85 assert.Equal(t, "john@doe.org", user) 86 87 isSSH, user = IsSSHURL("john@doe.org@john-server.org:29418/project") 88 assert.True(t, isSSH) 89 assert.Equal(t, "john@doe.org", user) 90 } 91 92 func TestSameURL(t *testing.T) { 93 data := map[string]string{ 94 "git@GITHUB.com:argoproj/test": "git@github.com:argoproj/test.git", 95 "git@GITHUB.com:argoproj/test.git": "git@github.com:argoproj/test.git", 96 "git@GITHUB.com:test": "git@github.com:test.git", 97 "git@GITHUB.com:test.git": "git@github.com:test.git", 98 "https://GITHUB.com/argoproj/test": "https://github.com/argoproj/test.git", 99 "https://GITHUB.com/argoproj/test.git": "https://github.com/argoproj/test.git", 100 "https://github.com/FOO": "https://github.com/foo", 101 "https://github.com/TEST": "https://github.com/TEST.git", 102 "https://github.com/TEST.git": "https://github.com/TEST.git", 103 "https://github.com:4443/TEST": "https://github.com:4443/TEST.git", 104 "https://github.com:4443/TEST.git": "https://github.com:4443/TEST", 105 "ssh://git@GITHUB.com/argoproj/test": "git@github.com:argoproj/test.git", 106 "ssh://git@GITHUB.com/argoproj/test.git": "git@github.com:argoproj/test.git", 107 "ssh://git@GITHUB.com/test.git": "git@github.com:test.git", 108 "ssh://git@github.com/test": "git@github.com:test.git", 109 " https://github.com/argoproj/test ": "https://github.com/argoproj/test.git", //nolint:gocritic // This includes whitespaces for testing 110 "\thttps://github.com/argoproj/test\n": "https://github.com/argoproj/test.git", 111 "https://1234.visualstudio.com/myproj/_git/myrepo": "https://1234.visualstudio.com/myproj/_git/myrepo", 112 "https://dev.azure.com/1234/myproj/_git/myrepo": "https://dev.azure.com/1234/myproj/_git/myrepo", 113 } 114 for k, v := range data { 115 assert.True(t, SameURL(k, v)) 116 } 117 } 118 119 func TestCustomHTTPClient(t *testing.T) { 120 certFile, err := filepath.Abs("../../test/fixture/certs/argocd-test-client.crt") 121 require.NoError(t, err) 122 assert.NotEmpty(t, certFile) 123 124 keyFile, err := filepath.Abs("../../test/fixture/certs/argocd-test-client.key") 125 require.NoError(t, err) 126 assert.NotEmpty(t, keyFile) 127 128 certData, err := os.ReadFile(certFile) 129 require.NoError(t, err) 130 assert.NotEmpty(t, string(certData)) 131 132 keyData, err := os.ReadFile(keyFile) 133 require.NoError(t, err) 134 assert.NotEmpty(t, string(keyData)) 135 136 // Get HTTPSCreds with client cert creds specified, and insecure connection 137 creds := NewHTTPSCreds("test", "test", "", string(certData), string(keyData), false, &NoopCredsStore{}, false) 138 client := GetRepoHTTPClient("https://localhost:9443/foo/bar", false, creds, "http://proxy:5000", "") 139 assert.NotNil(t, client) 140 assert.NotNil(t, client.Transport) 141 if client.Transport != nil { 142 transport := client.Transport.(*http.Transport) 143 assert.NotNil(t, transport.TLSClientConfig) 144 assert.True(t, transport.DisableKeepAlives) 145 assert.False(t, transport.TLSClientConfig.InsecureSkipVerify) 146 assert.NotNil(t, transport.TLSClientConfig.GetClientCertificate) 147 assert.Nil(t, transport.TLSClientConfig.RootCAs) 148 if transport.TLSClientConfig.GetClientCertificate != nil { 149 cert, err := transport.TLSClientConfig.GetClientCertificate(nil) 150 require.NoError(t, err) 151 if err == nil { 152 assert.NotNil(t, cert) 153 assert.NotEmpty(t, cert.Certificate) 154 assert.NotNil(t, cert.PrivateKey) 155 } 156 } 157 proxy, err := transport.Proxy(nil) 158 require.NoError(t, err) 159 assert.NotNil(t, proxy) // nil would mean no proxy is used 160 assert.Equal(t, "http://proxy:5000", proxy.String()) 161 } 162 163 t.Setenv("http_proxy", "http://proxy-from-env:7878") 164 165 // Get HTTPSCreds without client cert creds, but insecure connection 166 creds = NewHTTPSCreds("test", "test", "", "", "", true, &NoopCredsStore{}, false) 167 client = GetRepoHTTPClient("https://localhost:9443/foo/bar", true, creds, "", "") 168 assert.NotNil(t, client) 169 assert.NotNil(t, client.Transport) 170 if client.Transport != nil { 171 transport := client.Transport.(*http.Transport) 172 assert.NotNil(t, transport.TLSClientConfig) 173 assert.True(t, transport.DisableKeepAlives) 174 assert.True(t, transport.TLSClientConfig.InsecureSkipVerify) 175 assert.NotNil(t, transport.TLSClientConfig.GetClientCertificate) 176 assert.Nil(t, transport.TLSClientConfig.RootCAs) 177 if transport.TLSClientConfig.GetClientCertificate != nil { 178 cert, err := transport.TLSClientConfig.GetClientCertificate(nil) 179 require.NoError(t, err) 180 if err == nil { 181 assert.NotNil(t, cert) 182 assert.Empty(t, cert.Certificate) 183 assert.Nil(t, cert.PrivateKey) 184 } 185 } 186 req, err := http.NewRequest(http.MethodGet, "http://proxy-from-env:7878", http.NoBody) 187 require.NoError(t, err) 188 proxy, err := transport.Proxy(req) 189 require.NoError(t, err) 190 assert.Equal(t, "http://proxy-from-env:7878", proxy.String()) 191 } 192 // GetRepoHTTPClient with root ca 193 cert, err := os.ReadFile("../../test/fixture/certs/argocd-test-server.crt") 194 require.NoError(t, err) 195 temppath := t.TempDir() 196 defer os.RemoveAll(temppath) 197 err = os.WriteFile(filepath.Join(temppath, "127.0.0.1"), cert, 0o666) 198 require.NoError(t, err) 199 t.Setenv(common.EnvVarTLSDataPath, temppath) 200 client = GetRepoHTTPClient("https://127.0.0.1", false, creds, "", "") 201 assert.NotNil(t, client) 202 assert.NotNil(t, client.Transport) 203 if client.Transport != nil { 204 transport := client.Transport.(*http.Transport) 205 assert.NotNil(t, transport.TLSClientConfig) 206 assert.True(t, transport.DisableKeepAlives) 207 assert.False(t, transport.TLSClientConfig.InsecureSkipVerify) 208 assert.NotNil(t, transport.TLSClientConfig.RootCAs) 209 } 210 } 211 212 func TestLsRemote(t *testing.T) { 213 clnt, err := NewClientExt("https://github.com/argoproj/argo-cd.git", "/tmp", NopCreds{}, false, false, "", "") 214 require.NoError(t, err) 215 216 testCases := []struct { 217 name string 218 revision string 219 expectedCommit string 220 }{ 221 { 222 name: "should resolve symbolic link reference", 223 revision: "HEAD", 224 }, 225 { 226 name: "should resolve branch name", 227 revision: "master", 228 }, 229 { 230 name: "should resolve tag without semantic versioning", 231 revision: "release-0.8", 232 expectedCommit: "ff87d8cb9e669d3738434733ecba3c6dd2c64d70", 233 }, 234 { 235 name: "should resolve a pinned tag with semantic versioning", 236 revision: "v0.8.0", 237 expectedCommit: "d7c04ae24c16f8ec611b0331596fbc595537abe9", 238 }, 239 { 240 name: "should resolve a range tag with semantic versioning", 241 revision: "v0.8.*", // it should resolve to v0.8.2 242 expectedCommit: "e5eefa2b943ae14a3e4491d4e35ef082e1c2a3f4", 243 }, 244 { 245 name: "should resolve a range tag with semantic versioning without the 'v' prefix", 246 revision: "0.8.*", // it should resolve to v0.8.2 247 expectedCommit: "e5eefa2b943ae14a3e4491d4e35ef082e1c2a3f4", 248 }, 249 { 250 name: "should resolve a conditional range tag with semantic versioning", 251 revision: ">=v2.9.0 <2.10.4", // it should resolve to v2.10.3 252 expectedCommit: "0fd6344537eb948cff602824a1d060421ceff40e", 253 }, 254 { 255 name: "should resolve a star range tag with semantic versioning", 256 revision: "*", 257 }, 258 { 259 name: "should resolve a star range suffixed tag with semantic versioning", 260 revision: "*-0", 261 }, 262 { 263 name: "should resolve commit sha", 264 revision: "4e22a3cb21fa447ca362a05a505a69397c8a0d44", 265 expectedCommit: "4e22a3cb21fa447ca362a05a505a69397c8a0d44", 266 }, 267 } 268 269 for _, tc := range testCases { 270 t.Run(tc.name, func(t *testing.T) { 271 commitSHA, err := clnt.LsRemote(tc.revision) 272 require.NoError(t, err) 273 assert.True(t, IsCommitSHA(commitSHA)) 274 if tc.expectedCommit != "" { 275 assert.Equal(t, tc.expectedCommit, commitSHA) 276 } 277 }) 278 } 279 280 // We do not resolve truncated git hashes and return the commit as-is if it appears to be a commit 281 t.Run("truncated commit", func(t *testing.T) { 282 commitSHA, err := clnt.LsRemote("4e22a3c") 283 require.NoError(t, err) 284 assert.False(t, IsCommitSHA(commitSHA)) 285 assert.True(t, IsTruncatedCommitSHA(commitSHA)) 286 }) 287 288 t.Run("unresolvable revisions", func(t *testing.T) { 289 xfail := []string{ 290 "unresolvable", 291 "4e22a3", // too short (6 characters) 292 } 293 294 for _, revision := range xfail { 295 _, err := clnt.LsRemote(revision) 296 assert.ErrorContains(t, err, "unable to resolve") 297 } 298 }) 299 } 300 301 // Running this test requires git-lfs to be installed on your machine. 302 func TestLFSClient(t *testing.T) { 303 // temporary disable LFS test 304 // TODO(alexmt): dockerize tests in and enabled it 305 t.Skip() 306 307 tempDir := t.TempDir() 308 309 client, err := NewClientExt("https://github.com/argoproj-labs/argocd-testrepo-lfs", tempDir, NopCreds{}, false, true, "", "") 310 require.NoError(t, err) 311 312 commitSHA, err := client.LsRemote("HEAD") 313 require.NoError(t, err) 314 assert.NotEmpty(t, commitSHA) 315 316 err = client.Init() 317 require.NoError(t, err) 318 319 err = client.Fetch("") 320 require.NoError(t, err) 321 322 _, err = client.Checkout(commitSHA, true) 323 require.NoError(t, err) 324 325 largeFiles, err := client.LsLargeFiles() 326 require.NoError(t, err) 327 assert.Len(t, largeFiles, 3) 328 329 fileHandle, err := os.Open(tempDir + "/test3.yaml") 330 require.NoError(t, err) 331 if err == nil { 332 defer func() { 333 if err = fileHandle.Close(); err != nil { 334 require.NoError(t, err) 335 } 336 }() 337 text, err := io.ReadAll(fileHandle) 338 require.NoError(t, err) 339 if err == nil { 340 assert.Equal(t, "This is not a YAML, sorry.\n", string(text)) 341 } 342 } 343 } 344 345 func TestVerifyCommitSignature(t *testing.T) { 346 p := t.TempDir() 347 348 client, err := NewClientExt("https://github.com/argoproj/argo-cd.git", p, NopCreds{}, false, false, "", "") 349 require.NoError(t, err) 350 351 err = client.Init() 352 require.NoError(t, err) 353 354 err = client.Fetch("") 355 require.NoError(t, err) 356 357 commitSHA, err := client.LsRemote("HEAD") 358 require.NoError(t, err) 359 360 _, err = client.Checkout(commitSHA, true) 361 require.NoError(t, err) 362 363 // 28027897aad1262662096745f2ce2d4c74d02b7f is a commit that is signed in the repo 364 // It doesn't matter whether we know the key or not at this stage 365 { 366 out, err := client.VerifyCommitSignature("28027897aad1262662096745f2ce2d4c74d02b7f") 367 require.NoError(t, err) 368 assert.NotEmpty(t, out) 369 assert.Contains(t, out, "gpg: Signature made") 370 } 371 372 // 85d660f0b967960becce3d49bd51c678ba2a5d24 is a commit that is not signed 373 { 374 out, err := client.VerifyCommitSignature("85d660f0b967960becce3d49bd51c678ba2a5d24") 375 require.NoError(t, err) 376 assert.Empty(t, out) 377 } 378 } 379 380 func TestNewFactory(t *testing.T) { 381 addBinDirToPath := path.NewBinDirToPath(t) 382 defer addBinDirToPath.Close() 383 closer := log.Debug() 384 defer closer() 385 type args struct { 386 url string 387 insecureIgnoreHostKey bool 388 } 389 tests := []struct { 390 name string 391 args args 392 }{ 393 {"GitHub", args{url: "https://github.com/argoproj/argocd-example-apps"}}, 394 } 395 for _, tt := range tests { 396 if tt.name == "PrivateSSHRepo" { 397 test.Flaky(t) 398 } 399 400 dirName := t.TempDir() 401 402 client, err := NewClientExt(tt.args.url, dirName, NopCreds{}, tt.args.insecureIgnoreHostKey, false, "", "") 403 require.NoError(t, err) 404 commitSHA, err := client.LsRemote("HEAD") 405 require.NoError(t, err) 406 407 err = client.Init() 408 require.NoError(t, err) 409 410 err = client.Fetch("") 411 require.NoError(t, err) 412 413 // Do a second fetch to make sure we can treat `already up-to-date` error as not an error 414 err = client.Fetch("") 415 require.NoError(t, err) 416 417 _, err = client.Checkout(commitSHA, true) 418 require.NoError(t, err) 419 420 revisionMetadata, err := client.RevisionMetadata(commitSHA) 421 require.NoError(t, err) 422 assert.NotNil(t, revisionMetadata) 423 assert.Regexp(t, "^.*<.*>$", revisionMetadata.Author) 424 assert.Empty(t, revisionMetadata.Tags) 425 assert.NotEmpty(t, revisionMetadata.Date) 426 assert.NotEmpty(t, revisionMetadata.Message) 427 428 commitSHA2, err := client.CommitSHA() 429 require.NoError(t, err) 430 431 assert.Equal(t, commitSHA, commitSHA2) 432 } 433 } 434 435 func TestListRevisions(t *testing.T) { 436 dir := t.TempDir() 437 438 repoURL := "https://github.com/argoproj/argo-cd.git" 439 client, err := NewClientExt(repoURL, dir, NopCreds{}, false, false, "", "") 440 require.NoError(t, err) 441 442 lsResult, err := client.LsRefs() 443 require.NoError(t, err) 444 445 testBranch := "master" 446 testTag := "v1.0.0" 447 448 assert.Contains(t, lsResult.Branches, testBranch) 449 assert.Contains(t, lsResult.Tags, testTag) 450 assert.NotContains(t, lsResult.Branches, testTag) 451 assert.NotContains(t, lsResult.Tags, testBranch) 452 } 453 454 func TestLsFiles(t *testing.T) { 455 tmpDir1 := t.TempDir() 456 tmpDir2 := t.TempDir() 457 458 client, err := NewClientExt("", tmpDir1, NopCreds{}, false, false, "", "") 459 require.NoError(t, err) 460 461 require.NoError(t, runCmd(tmpDir1, "git", "init")) 462 463 // Setup files 464 require.NoError(t, os.WriteFile(filepath.Join(tmpDir1, "a.yaml"), []byte{}, 0o644)) 465 require.NoError(t, os.MkdirAll(filepath.Join(tmpDir1, "subdir"), 0o755)) 466 require.NoError(t, os.WriteFile(filepath.Join(tmpDir1, "subdir", "b.yaml"), []byte{}, 0o644)) 467 468 require.NoError(t, os.MkdirAll(filepath.Join(tmpDir2, "subdir"), 0o755)) 469 require.NoError(t, os.WriteFile(filepath.Join(tmpDir2, "c.yaml"), []byte{}, 0o644)) 470 471 require.NoError(t, os.Symlink(filepath.Join(tmpDir2, "c.yaml"), filepath.Join(tmpDir1, "link.yaml"))) 472 473 require.NoError(t, runCmd(tmpDir1, "git", "add", ".")) 474 require.NoError(t, runCmd(tmpDir1, "git", "commit", "-m", "Initial commit")) 475 476 tests := []struct { 477 name string 478 pattern string 479 safeGlobbing bool 480 expectedResult []string 481 }{ 482 { 483 name: "Old globbing with symlinks and subdir", 484 pattern: "*.yaml", 485 safeGlobbing: false, 486 expectedResult: []string{"a.yaml", "link.yaml", "subdir/b.yaml"}, 487 }, 488 { 489 name: "Safe globbing excludes symlinks", 490 pattern: "*.yaml", 491 safeGlobbing: true, 492 expectedResult: []string{"a.yaml"}, 493 }, 494 { 495 name: "Safe globbing excludes external paths", 496 pattern: filepath.Join(tmpDir2, "*.yaml"), 497 safeGlobbing: true, 498 expectedResult: nil, 499 }, 500 } 501 502 for _, tt := range tests { 503 t.Run(tt.name, func(t *testing.T) { 504 lsResult, err := client.LsFiles(tt.pattern, tt.safeGlobbing) 505 require.NoError(t, err) 506 assert.Equal(t, tt.expectedResult, lsResult) 507 }) 508 } 509 } 510 511 func TestLsFilesForGitFileGeneratorGlobbingPatterns(t *testing.T) { 512 tmpDir := t.TempDir() 513 514 client, err := NewClientExt("", tmpDir, NopCreds{}, false, false, "", "") 515 require.NoError(t, err) 516 517 err = runCmd(tmpDir, "git", "init") 518 require.NoError(t, err) 519 520 // Setup directory structure and files 521 files := []string{ 522 "cluster-charts/cluster1/mychart/charts/mysubchart/values.yaml", 523 "cluster-charts/cluster1/mychart/values.yaml", 524 "cluster-charts/cluster1/myotherchart/values.yaml", 525 "cluster-charts/cluster2/values.yaml", 526 "some-path/values.yaml", 527 "some-path/staging/values.yaml", 528 "cluster-config/engineering/production/config.json", 529 "cluster-config/engineering/dev/config.json", 530 "p1/p2/config.json", 531 "p1/app2/config.json", 532 "p1/app3/config.json", 533 "p1/config.json", 534 } 535 for _, file := range files { 536 dir := filepath.Dir(file) 537 require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, dir), 0o755)) 538 _, err := os.Create(filepath.Join(tmpDir, file)) 539 require.NoError(t, err) 540 } 541 require.NoError(t, runCmd(tmpDir, "git", "add", ".")) 542 require.NoError(t, runCmd(tmpDir, "git", "commit", "-m", "Initial commit")) 543 544 tests := []struct { 545 name string 546 pattern string 547 isNewGlobbingEnabled bool 548 expected []string 549 }{ 550 { 551 name: "**/config.json (isNewGlobbingEnabled)", 552 pattern: "**/config.json", 553 isNewGlobbingEnabled: true, 554 expected: []string{ 555 "cluster-config/engineering/production/config.json", 556 "cluster-config/engineering/dev/config.json", 557 "p1/config.json", 558 "p1/p2/config.json", 559 "p1/app2/config.json", 560 "p1/app3/config.json", 561 }, 562 }, 563 { 564 name: "**/config.json (non-isNewGlobbingEnabled)", 565 pattern: "**/config.json", 566 isNewGlobbingEnabled: false, 567 expected: []string{ 568 "cluster-config/engineering/production/config.json", 569 "cluster-config/engineering/dev/config.json", 570 "p1/config.json", 571 "p1/p2/config.json", 572 "p1/app2/config.json", 573 "p1/app3/config.json", 574 }, 575 }, 576 { 577 name: "some-path/*.yaml (isNewGlobbingEnabled)", 578 pattern: "some-path/*.yaml", 579 isNewGlobbingEnabled: true, 580 expected: []string{"some-path/values.yaml"}, 581 }, 582 { 583 name: "some-path/*.yaml (non-isNewGlobbingEnabled)", 584 pattern: "some-path/*.yaml", 585 isNewGlobbingEnabled: false, 586 expected: []string{ 587 "some-path/values.yaml", 588 "some-path/staging/values.yaml", 589 }, 590 }, 591 { 592 name: "p1/**/config.json (isNewGlobbingEnabled)", 593 pattern: "p1/**/config.json", 594 isNewGlobbingEnabled: true, 595 expected: []string{ 596 "p1/config.json", 597 "p1/p2/config.json", 598 "p1/app2/config.json", 599 "p1/app3/config.json", 600 }, 601 }, 602 { 603 name: "p1/**/config.json (non-isNewGlobbingEnabled)", 604 pattern: "p1/**/config.json", 605 isNewGlobbingEnabled: false, 606 expected: []string{ 607 "p1/p2/config.json", 608 "p1/app2/config.json", 609 "p1/app3/config.json", 610 }, 611 }, 612 { 613 name: "cluster-config/**/config.json (isNewGlobbingEnabled)", 614 pattern: "cluster-config/**/config.json", 615 isNewGlobbingEnabled: true, 616 expected: []string{ 617 "cluster-config/engineering/production/config.json", 618 "cluster-config/engineering/dev/config.json", 619 }, 620 }, 621 { 622 name: "cluster-config/**/config.json (isNewGlobbingEnabled=false)", 623 pattern: "cluster-config/**/config.json", 624 isNewGlobbingEnabled: false, 625 expected: []string{ 626 "cluster-config/engineering/dev/config.json", 627 "cluster-config/engineering/production/config.json", 628 }, 629 }, 630 { 631 name: "cluster-config/*/dev/config.json (isNewGlobbingEnabled)", 632 pattern: "cluster-config/*/dev/config.json", 633 isNewGlobbingEnabled: true, 634 expected: []string{"cluster-config/engineering/dev/config.json"}, 635 }, 636 { 637 name: "cluster-config/*/dev/config.json (isNewGlobbingEnabled=false)", 638 pattern: "cluster-config/*/dev/config.json", 639 isNewGlobbingEnabled: false, 640 expected: []string{"cluster-config/engineering/dev/config.json"}, 641 }, 642 { 643 name: "cluster-charts/*/*/values.yaml (isNewGlobbingEnabled)", 644 pattern: "cluster-charts/*/*/values.yaml", 645 isNewGlobbingEnabled: true, 646 expected: []string{ 647 "cluster-charts/cluster1/mychart/values.yaml", 648 "cluster-charts/cluster1/myotherchart/values.yaml", 649 }, 650 }, 651 { 652 name: "cluster-charts/*/*/values.yaml (isNewGlobbingEnabled=false)", 653 pattern: "cluster-charts/*/*/values.yaml", 654 isNewGlobbingEnabled: false, 655 expected: []string{ 656 "cluster-charts/cluster1/mychart/values.yaml", 657 "cluster-charts/cluster1/myotherchart/values.yaml", 658 "cluster-charts/cluster1/mychart/charts/mysubchart/values.yaml", 659 }, 660 }, 661 { 662 name: "cluster-charts/*/values.yaml (isNewGlobbingEnabled)", 663 pattern: "cluster-charts/*/values.yaml", 664 isNewGlobbingEnabled: true, 665 expected: []string{ 666 "cluster-charts/cluster2/values.yaml", 667 }, 668 }, 669 { 670 name: "cluster-charts/*/values.yaml (non-isNewGlobbingEnabled)", 671 pattern: "cluster-charts/*/values.yaml", 672 isNewGlobbingEnabled: false, 673 expected: []string{ 674 "cluster-charts/cluster2/values.yaml", 675 "cluster-charts/cluster1/mychart/values.yaml", 676 "cluster-charts/cluster1/myotherchart/values.yaml", 677 "cluster-charts/cluster1/mychart/charts/mysubchart/values.yaml", 678 }, 679 }, 680 } 681 682 for _, tt := range tests { 683 t.Run(tt.name, func(t *testing.T) { 684 lsResult, err := client.LsFiles(tt.pattern, tt.isNewGlobbingEnabled) 685 require.NoError(t, err) 686 assert.ElementsMatch(t, tt.expected, lsResult) 687 }) 688 } 689 } 690 691 func TestAnnotatedTagHandling(t *testing.T) { 692 dir := t.TempDir() 693 694 client, err := NewClientExt("https://github.com/argoproj/argo-cd.git", dir, NopCreds{}, false, false, "", "") 695 require.NoError(t, err) 696 697 err = client.Init() 698 require.NoError(t, err) 699 700 // Test annotated tag resolution 701 commitSHA, err := client.LsRemote("v1.0.0") // Known annotated tag 702 require.NoError(t, err) 703 704 // Verify we get commit SHA, not tag SHA 705 assert.True(t, IsCommitSHA(commitSHA)) 706 707 // Test tag reference handling 708 refs, err := client.LsRefs() 709 require.NoError(t, err) 710 711 // Verify tag exists in the list and points to a valid commit SHA 712 assert.Contains(t, refs.Tags, "v1.0.0", "Tag v1.0.0 should exist in refs") 713 }