fork of go-git with some jj specific features
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2.0 973 lines 28 kB view raw
1package git 2 3import ( 4 "bytes" 5 "context" 6 "errors" 7 "io" 8 "io/ioutil" 9 "os" 10 "runtime" 11 "time" 12 13 "github.com/go-git/go-git/v5/config" 14 "github.com/go-git/go-git/v5/plumbing" 15 "github.com/go-git/go-git/v5/plumbing/cache" 16 "github.com/go-git/go-git/v5/plumbing/protocol/packp" 17 "github.com/go-git/go-git/v5/plumbing/protocol/packp/capability" 18 "github.com/go-git/go-git/v5/plumbing/storer" 19 "github.com/go-git/go-git/v5/storage" 20 "github.com/go-git/go-git/v5/storage/filesystem" 21 "github.com/go-git/go-git/v5/storage/memory" 22 23 "github.com/go-git/go-billy/v5/osfs" 24 fixtures "github.com/go-git/go-git-fixtures/v4" 25 . "gopkg.in/check.v1" 26) 27 28type RemoteSuite struct { 29 BaseSuite 30} 31 32var _ = Suite(&RemoteSuite{}) 33 34func (s *RemoteSuite) TestFetchInvalidEndpoint(c *C) { 35 r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"http://\\"}}) 36 err := r.Fetch(&FetchOptions{RemoteName: "foo"}) 37 c.Assert(err, ErrorMatches, ".*invalid character.*") 38} 39 40func (s *RemoteSuite) TestFetchNonExistentEndpoint(c *C) { 41 r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"ssh://non-existent/foo.git"}}) 42 err := r.Fetch(&FetchOptions{}) 43 c.Assert(err, NotNil) 44} 45 46func (s *RemoteSuite) TestFetchInvalidSchemaEndpoint(c *C) { 47 r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) 48 err := r.Fetch(&FetchOptions{}) 49 c.Assert(err, ErrorMatches, ".*unsupported scheme.*") 50} 51 52func (s *RemoteSuite) TestFetchInvalidFetchOptions(c *C) { 53 r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) 54 invalid := config.RefSpec("^*$ñ") 55 err := r.Fetch(&FetchOptions{RefSpecs: []config.RefSpec{invalid}}) 56 c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) 57} 58 59func (s *RemoteSuite) TestFetchWildcard(c *C) { 60 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 61 URLs: []string{s.GetBasicLocalRepositoryURL()}, 62 }) 63 64 s.testFetch(c, r, &FetchOptions{ 65 RefSpecs: []config.RefSpec{ 66 config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), 67 }, 68 }, []*plumbing.Reference{ 69 plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 70 plumbing.NewReferenceFromStrings("refs/remotes/origin/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), 71 plumbing.NewReferenceFromStrings("refs/tags/v1.0.0", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 72 }) 73} 74 75func (s *RemoteSuite) TestFetchExactSHA1(c *C) { 76 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 77 URLs: []string{"https://github.com/git-fixtures/basic.git"}, 78 }) 79 80 s.testFetch(c, r, &FetchOptions{ 81 RefSpecs: []config.RefSpec{ 82 config.RefSpec("35e85108805c84807bc66a02d91535e1e24b38b9:refs/heads/foo"), 83 }, 84 }, []*plumbing.Reference{ 85 plumbing.NewReferenceFromStrings("refs/heads/foo", "35e85108805c84807bc66a02d91535e1e24b38b9"), 86 }) 87} 88 89func (s *RemoteSuite) TestFetchExactSHA1_NotSoported(c *C) { 90 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 91 URLs: []string{s.GetBasicLocalRepositoryURL()}, 92 }) 93 94 err := r.Fetch(&FetchOptions{ 95 RefSpecs: []config.RefSpec{ 96 config.RefSpec("35e85108805c84807bc66a02d91535e1e24b38b9:refs/heads/foo"), 97 }, 98 }) 99 100 c.Assert(err, Equals, ErrExactSHA1NotSupported) 101 102} 103 104func (s *RemoteSuite) TestFetchWildcardTags(c *C) { 105 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 106 URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, 107 }) 108 109 s.testFetch(c, r, &FetchOptions{ 110 RefSpecs: []config.RefSpec{ 111 config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), 112 }, 113 }, []*plumbing.Reference{ 114 plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), 115 plumbing.NewReferenceFromStrings("refs/tags/annotated-tag", "b742a2a9fa0afcfa9a6fad080980fbc26b007c69"), 116 plumbing.NewReferenceFromStrings("refs/tags/tree-tag", "152175bf7e5580299fa1f0ba41ef6474cc043b70"), 117 plumbing.NewReferenceFromStrings("refs/tags/commit-tag", "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc"), 118 plumbing.NewReferenceFromStrings("refs/tags/blob-tag", "fe6cb94756faa81e5ed9240f9191b833db5f40ae"), 119 plumbing.NewReferenceFromStrings("refs/tags/lightweight-tag", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), 120 }) 121} 122 123func (s *RemoteSuite) TestFetch(c *C) { 124 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 125 URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, 126 }) 127 128 s.testFetch(c, r, &FetchOptions{ 129 RefSpecs: []config.RefSpec{ 130 config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), 131 }, 132 }, []*plumbing.Reference{ 133 plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), 134 }) 135} 136 137func (s *RemoteSuite) TestFetchNonExistantReference(c *C) { 138 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 139 URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, 140 }) 141 142 err := r.Fetch(&FetchOptions{ 143 RefSpecs: []config.RefSpec{ 144 config.RefSpec("+refs/heads/foo:refs/remotes/origin/foo"), 145 }, 146 }) 147 148 c.Assert(err, ErrorMatches, "couldn't find remote ref.*") 149 c.Assert(errors.Is(err, NoMatchingRefSpecError{}), Equals, true) 150} 151 152func (s *RemoteSuite) TestFetchContext(c *C) { 153 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 154 URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, 155 }) 156 157 ctx, cancel := context.WithCancel(context.Background()) 158 cancel() 159 160 err := r.FetchContext(ctx, &FetchOptions{ 161 RefSpecs: []config.RefSpec{ 162 config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), 163 }, 164 }) 165 c.Assert(err, NotNil) 166} 167 168func (s *RemoteSuite) TestFetchWithAllTags(c *C) { 169 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 170 URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, 171 }) 172 173 s.testFetch(c, r, &FetchOptions{ 174 Tags: AllTags, 175 RefSpecs: []config.RefSpec{ 176 config.RefSpec("+refs/heads/master:refs/remotes/origin/master"), 177 }, 178 }, []*plumbing.Reference{ 179 plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), 180 plumbing.NewReferenceFromStrings("refs/tags/annotated-tag", "b742a2a9fa0afcfa9a6fad080980fbc26b007c69"), 181 plumbing.NewReferenceFromStrings("refs/tags/tree-tag", "152175bf7e5580299fa1f0ba41ef6474cc043b70"), 182 plumbing.NewReferenceFromStrings("refs/tags/commit-tag", "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc"), 183 plumbing.NewReferenceFromStrings("refs/tags/blob-tag", "fe6cb94756faa81e5ed9240f9191b833db5f40ae"), 184 plumbing.NewReferenceFromStrings("refs/tags/lightweight-tag", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), 185 }) 186} 187 188func (s *RemoteSuite) TestFetchWithNoTags(c *C) { 189 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 190 URLs: []string{s.GetLocalRepositoryURL(fixtures.ByTag("tags").One())}, 191 }) 192 193 s.testFetch(c, r, &FetchOptions{ 194 Tags: NoTags, 195 RefSpecs: []config.RefSpec{ 196 config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), 197 }, 198 }, []*plumbing.Reference{ 199 plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"), 200 }) 201 202} 203 204func (s *RemoteSuite) TestFetchWithDepth(c *C) { 205 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 206 URLs: []string{s.GetBasicLocalRepositoryURL()}, 207 }) 208 209 s.testFetch(c, r, &FetchOptions{ 210 Depth: 1, 211 RefSpecs: []config.RefSpec{ 212 config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), 213 }, 214 }, []*plumbing.Reference{ 215 plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 216 plumbing.NewReferenceFromStrings("refs/remotes/origin/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), 217 plumbing.NewReferenceFromStrings("refs/tags/v1.0.0", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 218 }) 219 220 c.Assert(r.s.(*memory.Storage).Objects, HasLen, 18) 221} 222 223func (s *RemoteSuite) testFetch(c *C, r *Remote, o *FetchOptions, expected []*plumbing.Reference) { 224 err := r.Fetch(o) 225 c.Assert(err, IsNil) 226 227 var refs int 228 l, err := r.s.IterReferences() 229 c.Assert(err, IsNil) 230 l.ForEach(func(r *plumbing.Reference) error { refs++; return nil }) 231 232 c.Assert(refs, Equals, len(expected)) 233 234 for _, exp := range expected { 235 r, err := r.s.Reference(exp.Name()) 236 c.Assert(err, IsNil) 237 c.Assert(exp.String(), Equals, r.String()) 238 } 239} 240 241func (s *RemoteSuite) TestFetchWithProgress(c *C) { 242 url := s.GetBasicLocalRepositoryURL() 243 sto := memory.NewStorage() 244 buf := bytes.NewBuffer(nil) 245 246 r := NewRemote(sto, &config.RemoteConfig{Name: "foo", URLs: []string{url}}) 247 248 refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*") 249 err := r.Fetch(&FetchOptions{ 250 RefSpecs: []config.RefSpec{refspec}, 251 Progress: buf, 252 }) 253 254 c.Assert(err, IsNil) 255 c.Assert(sto.Objects, HasLen, 31) 256 257 c.Assert(buf.Len(), Not(Equals), 0) 258} 259 260type mockPackfileWriter struct { 261 storage.Storer 262 PackfileWriterCalled bool 263} 264 265func (m *mockPackfileWriter) PackfileWriter() (io.WriteCloser, error) { 266 m.PackfileWriterCalled = true 267 return m.Storer.(storer.PackfileWriter).PackfileWriter() 268} 269 270func (s *RemoteSuite) TestFetchWithPackfileWriter(c *C) { 271 dir, err := ioutil.TempDir("", "fetch") 272 c.Assert(err, IsNil) 273 274 defer os.RemoveAll(dir) // clean up 275 276 fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) 277 c.Assert(err, IsNil) 278 279 mock := &mockPackfileWriter{Storer: fss} 280 281 url := s.GetBasicLocalRepositoryURL() 282 r := NewRemote(mock, &config.RemoteConfig{Name: "foo", URLs: []string{url}}) 283 284 refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*") 285 err = r.Fetch(&FetchOptions{ 286 RefSpecs: []config.RefSpec{refspec}, 287 }) 288 289 c.Assert(err, IsNil) 290 291 var count int 292 iter, err := mock.IterEncodedObjects(plumbing.AnyObject) 293 c.Assert(err, IsNil) 294 295 iter.ForEach(func(plumbing.EncodedObject) error { 296 count++ 297 return nil 298 }) 299 300 c.Assert(count, Equals, 31) 301 c.Assert(mock.PackfileWriterCalled, Equals, true) 302} 303 304func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDate(c *C) { 305 url := s.GetBasicLocalRepositoryURL() 306 s.doTestFetchNoErrAlreadyUpToDate(c, url) 307} 308 309func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateButStillUpdateLocalRemoteRefs(c *C) { 310 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 311 URLs: []string{s.GetBasicLocalRepositoryURL()}, 312 }) 313 314 o := &FetchOptions{ 315 RefSpecs: []config.RefSpec{ 316 config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), 317 }, 318 } 319 320 err := r.Fetch(o) 321 c.Assert(err, IsNil) 322 323 // Simulate an out of date remote ref even though we have the new commit locally 324 r.s.SetReference(plumbing.NewReferenceFromStrings( 325 "refs/remotes/origin/master", "918c48b83bd081e863dbe1b80f8998f058cd8294", 326 )) 327 328 err = r.Fetch(o) 329 c.Assert(err, IsNil) 330 331 exp := plumbing.NewReferenceFromStrings( 332 "refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", 333 ) 334 335 ref, err := r.s.Reference("refs/remotes/origin/master") 336 c.Assert(err, IsNil) 337 c.Assert(exp.String(), Equals, ref.String()) 338} 339 340func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateWithNonCommitObjects(c *C) { 341 fixture := fixtures.ByTag("tags").One() 342 url := s.GetLocalRepositoryURL(fixture) 343 s.doTestFetchNoErrAlreadyUpToDate(c, url) 344} 345 346func (s *RemoteSuite) doTestFetchNoErrAlreadyUpToDate(c *C, url string) { 347 r := NewRemote(memory.NewStorage(), &config.RemoteConfig{URLs: []string{url}}) 348 349 o := &FetchOptions{ 350 RefSpecs: []config.RefSpec{ 351 config.RefSpec("+refs/heads/*:refs/remotes/origin/*"), 352 }, 353 } 354 355 err := r.Fetch(o) 356 c.Assert(err, IsNil) 357 err = r.Fetch(o) 358 c.Assert(err, Equals, NoErrAlreadyUpToDate) 359} 360 361func (s *RemoteSuite) testFetchFastForward(c *C, sto storage.Storer) { 362 r := NewRemote(sto, &config.RemoteConfig{ 363 URLs: []string{s.GetBasicLocalRepositoryURL()}, 364 }) 365 366 s.testFetch(c, r, &FetchOptions{ 367 RefSpecs: []config.RefSpec{ 368 config.RefSpec("+refs/heads/master:refs/heads/master"), 369 }, 370 }, []*plumbing.Reference{ 371 plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 372 }) 373 374 // First make sure that we error correctly when a force is required. 375 err := r.Fetch(&FetchOptions{ 376 RefSpecs: []config.RefSpec{ 377 config.RefSpec("refs/heads/branch:refs/heads/master"), 378 }, 379 }) 380 c.Assert(err, Equals, ErrForceNeeded) 381 382 // And that forcing it fixes the problem. 383 err = r.Fetch(&FetchOptions{ 384 RefSpecs: []config.RefSpec{ 385 config.RefSpec("+refs/heads/branch:refs/heads/master"), 386 }, 387 }) 388 c.Assert(err, IsNil) 389 390 // Now test that a fast-forward, non-force fetch works. 391 r.s.SetReference(plumbing.NewReferenceFromStrings( 392 "refs/heads/master", "918c48b83bd081e863dbe1b80f8998f058cd8294", 393 )) 394 s.testFetch(c, r, &FetchOptions{ 395 RefSpecs: []config.RefSpec{ 396 config.RefSpec("refs/heads/master:refs/heads/master"), 397 }, 398 }, []*plumbing.Reference{ 399 plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 400 }) 401} 402 403func (s *RemoteSuite) TestFetchFastForwardMem(c *C) { 404 s.testFetchFastForward(c, memory.NewStorage()) 405} 406 407func (s *RemoteSuite) TestFetchFastForwardFS(c *C) { 408 dir, err := ioutil.TempDir("", "fetch") 409 c.Assert(err, IsNil) 410 411 defer os.RemoveAll(dir) // clean up 412 413 fss := filesystem.NewStorage(osfs.New(dir), cache.NewObjectLRUDefault()) 414 415 // This exercises `storage.filesystem.Storage.CheckAndSetReference()`. 416 s.testFetchFastForward(c, fss) 417} 418 419func (s *RemoteSuite) TestString(c *C) { 420 r := NewRemote(nil, &config.RemoteConfig{ 421 Name: "foo", 422 URLs: []string{"https://github.com/git-fixtures/basic.git"}, 423 }) 424 425 c.Assert(r.String(), Equals, ""+ 426 "foo\thttps://github.com/git-fixtures/basic.git (fetch)\n"+ 427 "foo\thttps://github.com/git-fixtures/basic.git (push)", 428 ) 429} 430 431func (s *RemoteSuite) TestPushToEmptyRepository(c *C) { 432 url := c.MkDir() 433 server, err := PlainInit(url, true) 434 c.Assert(err, IsNil) 435 436 srcFs := fixtures.Basic().One().DotGit() 437 sto := filesystem.NewStorage(srcFs, cache.NewObjectLRUDefault()) 438 439 r := NewRemote(sto, &config.RemoteConfig{ 440 Name: DefaultRemoteName, 441 URLs: []string{url}, 442 }) 443 444 rs := config.RefSpec("refs/heads/*:refs/heads/*") 445 err = r.Push(&PushOptions{ 446 RefSpecs: []config.RefSpec{rs}, 447 }) 448 c.Assert(err, IsNil) 449 450 iter, err := r.s.IterReferences() 451 c.Assert(err, IsNil) 452 453 expected := make(map[string]string) 454 iter.ForEach(func(ref *plumbing.Reference) error { 455 if !ref.Name().IsBranch() { 456 return nil 457 } 458 459 expected[ref.Name().String()] = ref.Hash().String() 460 return nil 461 }) 462 c.Assert(err, IsNil) 463 464 AssertReferences(c, server, expected) 465 466} 467 468func (s *RemoteSuite) TestPushContext(c *C) { 469 url := c.MkDir() 470 _, err := PlainInit(url, true) 471 c.Assert(err, IsNil) 472 473 fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() 474 sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 475 476 r := NewRemote(sto, &config.RemoteConfig{ 477 Name: DefaultRemoteName, 478 URLs: []string{url}, 479 }) 480 481 ctx, cancel := context.WithCancel(context.Background()) 482 cancel() 483 484 numGoroutines := runtime.NumGoroutine() 485 486 err = r.PushContext(ctx, &PushOptions{ 487 RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"}, 488 }) 489 c.Assert(err, NotNil) 490 491 // let the goroutine from pushHashes finish and check that the number of 492 // goroutines is the same as before 493 time.Sleep(100 * time.Millisecond) 494 c.Assert(runtime.NumGoroutine(), Equals, numGoroutines) 495} 496 497func (s *RemoteSuite) TestPushTags(c *C) { 498 url := c.MkDir() 499 server, err := PlainInit(url, true) 500 c.Assert(err, IsNil) 501 502 fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() 503 sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 504 505 r := NewRemote(sto, &config.RemoteConfig{ 506 Name: DefaultRemoteName, 507 URLs: []string{url}, 508 }) 509 510 err = r.Push(&PushOptions{ 511 RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"}, 512 }) 513 c.Assert(err, IsNil) 514 515 AssertReferences(c, server, map[string]string{ 516 "refs/tags/lightweight-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", 517 "refs/tags/annotated-tag": "b742a2a9fa0afcfa9a6fad080980fbc26b007c69", 518 "refs/tags/commit-tag": "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc", 519 "refs/tags/blob-tag": "fe6cb94756faa81e5ed9240f9191b833db5f40ae", 520 "refs/tags/tree-tag": "152175bf7e5580299fa1f0ba41ef6474cc043b70", 521 }) 522} 523 524func (s *RemoteSuite) TestPushNoErrAlreadyUpToDate(c *C) { 525 fs := fixtures.Basic().One().DotGit() 526 sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 527 528 r := NewRemote(sto, &config.RemoteConfig{ 529 Name: DefaultRemoteName, 530 URLs: []string{fs.Root()}, 531 }) 532 533 err := r.Push(&PushOptions{ 534 RefSpecs: []config.RefSpec{"refs/heads/*:refs/heads/*"}, 535 }) 536 c.Assert(err, Equals, NoErrAlreadyUpToDate) 537} 538 539func (s *RemoteSuite) TestPushDeleteReference(c *C) { 540 fs := fixtures.Basic().One().DotGit() 541 sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 542 543 r, err := PlainClone(c.MkDir(), true, &CloneOptions{ 544 URL: fs.Root(), 545 }) 546 c.Assert(err, IsNil) 547 548 remote, err := r.Remote(DefaultRemoteName) 549 c.Assert(err, IsNil) 550 551 err = remote.Push(&PushOptions{ 552 RefSpecs: []config.RefSpec{":refs/heads/branch"}, 553 }) 554 c.Assert(err, IsNil) 555 556 _, err = sto.Reference(plumbing.ReferenceName("refs/heads/branch")) 557 c.Assert(err, Equals, plumbing.ErrReferenceNotFound) 558 559 _, err = r.Storer.Reference(plumbing.ReferenceName("refs/heads/branch")) 560 c.Assert(err, Equals, plumbing.ErrReferenceNotFound) 561} 562 563func (s *RemoteSuite) TestForcePushDeleteReference(c *C) { 564 fs := fixtures.Basic().One().DotGit() 565 sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 566 567 r, err := PlainClone(c.MkDir(), true, &CloneOptions{ 568 URL: fs.Root(), 569 }) 570 c.Assert(err, IsNil) 571 572 remote, err := r.Remote(DefaultRemoteName) 573 c.Assert(err, IsNil) 574 575 err = remote.Push(&PushOptions{ 576 RefSpecs: []config.RefSpec{":refs/heads/branch"}, 577 Force: true, 578 }) 579 c.Assert(err, IsNil) 580 581 _, err = sto.Reference(plumbing.ReferenceName("refs/heads/branch")) 582 c.Assert(err, Equals, plumbing.ErrReferenceNotFound) 583 584 _, err = r.Storer.Reference(plumbing.ReferenceName("refs/heads/branch")) 585 c.Assert(err, Equals, plumbing.ErrReferenceNotFound) 586} 587 588func (s *RemoteSuite) TestPushRejectNonFastForward(c *C) { 589 fs := fixtures.Basic().One().DotGit() 590 server := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 591 592 r, err := PlainClone(c.MkDir(), true, &CloneOptions{ 593 URL: fs.Root(), 594 }) 595 c.Assert(err, IsNil) 596 597 remote, err := r.Remote(DefaultRemoteName) 598 c.Assert(err, IsNil) 599 600 branch := plumbing.ReferenceName("refs/heads/branch") 601 oldRef, err := server.Reference(branch) 602 c.Assert(err, IsNil) 603 c.Assert(oldRef, NotNil) 604 605 err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ 606 "refs/heads/master:refs/heads/branch", 607 }}) 608 c.Assert(err, ErrorMatches, "non-fast-forward update: refs/heads/branch") 609 610 newRef, err := server.Reference(branch) 611 c.Assert(err, IsNil) 612 c.Assert(newRef, DeepEquals, oldRef) 613} 614 615func (s *RemoteSuite) TestPushForce(c *C) { 616 f := fixtures.Basic().One() 617 sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) 618 619 dstFs := f.DotGit() 620 dstSto := filesystem.NewStorage(dstFs, cache.NewObjectLRUDefault()) 621 622 url := dstFs.Root() 623 r := NewRemote(sto, &config.RemoteConfig{ 624 Name: DefaultRemoteName, 625 URLs: []string{url}, 626 }) 627 628 oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch")) 629 c.Assert(err, IsNil) 630 c.Assert(oldRef, NotNil) 631 632 err = r.Push(&PushOptions{RefSpecs: []config.RefSpec{ 633 config.RefSpec("+refs/heads/master:refs/heads/branch"), 634 }}) 635 c.Assert(err, IsNil) 636 637 newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch")) 638 c.Assert(err, IsNil) 639 c.Assert(newRef, Not(DeepEquals), oldRef) 640} 641 642func (s *RemoteSuite) TestPushForceWithOption(c *C) { 643 f := fixtures.Basic().One() 644 sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) 645 646 dstFs := f.DotGit() 647 dstSto := filesystem.NewStorage(dstFs, cache.NewObjectLRUDefault()) 648 649 url := dstFs.Root() 650 r := NewRemote(sto, &config.RemoteConfig{ 651 Name: DefaultRemoteName, 652 URLs: []string{url}, 653 }) 654 655 oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch")) 656 c.Assert(err, IsNil) 657 c.Assert(oldRef, NotNil) 658 659 err = r.Push(&PushOptions{ 660 RefSpecs: []config.RefSpec{"refs/heads/master:refs/heads/branch"}, 661 Force: true, 662 }) 663 c.Assert(err, IsNil) 664 665 newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch")) 666 c.Assert(err, IsNil) 667 c.Assert(newRef, Not(DeepEquals), oldRef) 668} 669 670func (s *RemoteSuite) TestPushPrune(c *C) { 671 fs := fixtures.Basic().One().DotGit() 672 url := c.MkDir() 673 server, err := PlainClone(url, true, &CloneOptions{ 674 URL: fs.Root(), 675 }) 676 c.Assert(err, IsNil) 677 678 r, err := PlainClone(c.MkDir(), true, &CloneOptions{ 679 URL: url, 680 }) 681 c.Assert(err, IsNil) 682 683 tag, err := r.Reference(plumbing.ReferenceName("refs/tags/v1.0.0"), true) 684 c.Assert(err, IsNil) 685 686 err = r.DeleteTag("v1.0.0") 687 c.Assert(err, IsNil) 688 689 remote, err := r.Remote(DefaultRemoteName) 690 c.Assert(err, IsNil) 691 692 ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) 693 c.Assert(err, IsNil) 694 695 err = remote.Push(&PushOptions{ 696 RefSpecs: []config.RefSpec{ 697 config.RefSpec("refs/heads/*:refs/heads/*"), 698 }, 699 Prune: true, 700 }) 701 c.Assert(err, Equals, NoErrAlreadyUpToDate) 702 703 AssertReferences(c, server, map[string]string{ 704 "refs/tags/v1.0.0": tag.Hash().String(), 705 }) 706 707 err = remote.Push(&PushOptions{ 708 RefSpecs: []config.RefSpec{ 709 config.RefSpec("*:*"), 710 }, 711 Prune: true, 712 }) 713 c.Assert(err, IsNil) 714 715 AssertReferences(c, server, map[string]string{ 716 "refs/remotes/origin/master": ref.Hash().String(), 717 }) 718 719 AssertReferences(c, server, map[string]string{ 720 "refs/remotes/origin/master": ref.Hash().String(), 721 }) 722 723 ref, err = server.Reference(plumbing.ReferenceName("refs/tags/v1.0.0"), true) 724 c.Assert(err, Equals, plumbing.ErrReferenceNotFound) 725} 726 727func (s *RemoteSuite) TestPushNewReference(c *C) { 728 fs := fixtures.Basic().One().DotGit() 729 url := c.MkDir() 730 server, err := PlainClone(url, true, &CloneOptions{ 731 URL: fs.Root(), 732 }) 733 c.Assert(err, IsNil) 734 735 r, err := PlainClone(c.MkDir(), true, &CloneOptions{ 736 URL: url, 737 }) 738 c.Assert(err, IsNil) 739 740 remote, err := r.Remote(DefaultRemoteName) 741 c.Assert(err, IsNil) 742 743 ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) 744 c.Assert(err, IsNil) 745 746 err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ 747 "refs/heads/master:refs/heads/branch2", 748 }}) 749 c.Assert(err, IsNil) 750 751 AssertReferences(c, server, map[string]string{ 752 "refs/heads/branch2": ref.Hash().String(), 753 }) 754 755 AssertReferences(c, r, map[string]string{ 756 "refs/remotes/origin/branch2": ref.Hash().String(), 757 }) 758} 759 760func (s *RemoteSuite) TestPushNewReferenceAndDeleteInBatch(c *C) { 761 fs := fixtures.Basic().One().DotGit() 762 url := c.MkDir() 763 server, err := PlainClone(url, true, &CloneOptions{ 764 URL: fs.Root(), 765 }) 766 c.Assert(err, IsNil) 767 768 r, err := PlainClone(c.MkDir(), true, &CloneOptions{ 769 URL: url, 770 }) 771 c.Assert(err, IsNil) 772 773 remote, err := r.Remote(DefaultRemoteName) 774 c.Assert(err, IsNil) 775 776 ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true) 777 c.Assert(err, IsNil) 778 779 err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{ 780 "refs/heads/master:refs/heads/branch2", 781 ":refs/heads/branch", 782 }}) 783 c.Assert(err, IsNil) 784 785 AssertReferences(c, server, map[string]string{ 786 "refs/heads/branch2": ref.Hash().String(), 787 }) 788 789 AssertReferences(c, r, map[string]string{ 790 "refs/remotes/origin/branch2": ref.Hash().String(), 791 }) 792 793 _, err = server.Storer.Reference(plumbing.ReferenceName("refs/heads/branch")) 794 c.Assert(err, Equals, plumbing.ErrReferenceNotFound) 795} 796 797func (s *RemoteSuite) TestPushInvalidEndpoint(c *C) { 798 r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"http://\\"}}) 799 err := r.Push(&PushOptions{RemoteName: "foo"}) 800 c.Assert(err, ErrorMatches, ".*invalid character.*") 801} 802 803func (s *RemoteSuite) TestPushNonExistentEndpoint(c *C) { 804 r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"ssh://non-existent/foo.git"}}) 805 err := r.Push(&PushOptions{}) 806 c.Assert(err, NotNil) 807} 808 809func (s *RemoteSuite) TestPushInvalidSchemaEndpoint(c *C) { 810 r := NewRemote(nil, &config.RemoteConfig{Name: "origin", URLs: []string{"qux://foo"}}) 811 err := r.Push(&PushOptions{}) 812 c.Assert(err, ErrorMatches, ".*unsupported scheme.*") 813} 814 815func (s *RemoteSuite) TestPushInvalidFetchOptions(c *C) { 816 r := NewRemote(nil, &config.RemoteConfig{Name: "foo", URLs: []string{"qux://foo"}}) 817 invalid := config.RefSpec("^*$ñ") 818 err := r.Push(&PushOptions{RefSpecs: []config.RefSpec{invalid}}) 819 c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) 820} 821 822func (s *RemoteSuite) TestPushInvalidRefSpec(c *C) { 823 r := NewRemote(nil, &config.RemoteConfig{ 824 Name: DefaultRemoteName, 825 URLs: []string{"some-url"}, 826 }) 827 828 rs := config.RefSpec("^*$**") 829 err := r.Push(&PushOptions{ 830 RefSpecs: []config.RefSpec{rs}, 831 }) 832 c.Assert(err, Equals, config.ErrRefSpecMalformedSeparator) 833} 834 835func (s *RemoteSuite) TestPushWrongRemoteName(c *C) { 836 r := NewRemote(nil, &config.RemoteConfig{ 837 Name: DefaultRemoteName, 838 URLs: []string{"some-url"}, 839 }) 840 841 err := r.Push(&PushOptions{ 842 RemoteName: "other-remote", 843 }) 844 c.Assert(err, ErrorMatches, ".*remote names don't match.*") 845} 846 847func (s *RemoteSuite) TestGetHaves(c *C) { 848 f := fixtures.Basic().One() 849 sto := filesystem.NewStorage(f.DotGit(), cache.NewObjectLRUDefault()) 850 851 var localRefs = []*plumbing.Reference{ 852 plumbing.NewReferenceFromStrings( 853 "foo", 854 "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", 855 ), 856 plumbing.NewReferenceFromStrings( 857 "bar", 858 "fe6cb94756faa81e5ed9240f9191b833db5f40ae", 859 ), 860 plumbing.NewReferenceFromStrings( 861 "qux", 862 "f7b877701fbf855b44c0a9e86f3fdce2c298b07f", 863 ), 864 } 865 866 l, err := getHaves(localRefs, memory.NewStorage(), sto) 867 c.Assert(err, IsNil) 868 c.Assert(l, HasLen, 2) 869} 870 871func (s *RemoteSuite) TestList(c *C) { 872 repo := fixtures.Basic().One() 873 remote := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 874 Name: DefaultRemoteName, 875 URLs: []string{repo.URL}, 876 }) 877 878 refs, err := remote.List(&ListOptions{}) 879 c.Assert(err, IsNil) 880 881 expected := []*plumbing.Reference{ 882 plumbing.NewSymbolicReference("HEAD", "refs/heads/master"), 883 plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"), 884 plumbing.NewReferenceFromStrings("refs/heads/branch", "e8d3ffab552895c19b9fcf7aa264d277cde33881"), 885 plumbing.NewReferenceFromStrings("refs/pull/1/head", "b8e471f58bcbca63b07bda20e428190409c2db47"), 886 plumbing.NewReferenceFromStrings("refs/pull/2/head", "9632f02833b2f9613afb5e75682132b0b22e4a31"), 887 plumbing.NewReferenceFromStrings("refs/pull/2/merge", "c37f58a130ca555e42ff96a071cb9ccb3f437504"), 888 } 889 c.Assert(len(refs), Equals, len(expected)) 890 for _, e := range expected { 891 found := false 892 for _, r := range refs { 893 if r.Name() == e.Name() { 894 found = true 895 c.Assert(r, DeepEquals, e) 896 } 897 } 898 c.Assert(found, Equals, true) 899 } 900} 901 902func (s *RemoteSuite) TestUpdateShallows(c *C) { 903 hashes := []plumbing.Hash{ 904 plumbing.NewHash("0000000000000000000000000000000000000001"), 905 plumbing.NewHash("0000000000000000000000000000000000000002"), 906 plumbing.NewHash("0000000000000000000000000000000000000003"), 907 plumbing.NewHash("0000000000000000000000000000000000000004"), 908 plumbing.NewHash("0000000000000000000000000000000000000005"), 909 plumbing.NewHash("0000000000000000000000000000000000000006"), 910 } 911 912 tests := []struct { 913 hashes []plumbing.Hash 914 result []plumbing.Hash 915 }{ 916 // add to empty shallows 917 {hashes[0:2], hashes[0:2]}, 918 // add new hashes 919 {hashes[2:4], hashes[0:4]}, 920 // add some hashes already in shallow list 921 {hashes[2:6], hashes[0:6]}, 922 // add all hashes 923 {hashes[0:6], hashes[0:6]}, 924 // add empty list 925 {nil, hashes[0:6]}, 926 } 927 928 remote := NewRemote(memory.NewStorage(), &config.RemoteConfig{ 929 Name: DefaultRemoteName, 930 }) 931 932 shallows, err := remote.s.Shallow() 933 c.Assert(err, IsNil) 934 c.Assert(len(shallows), Equals, 0) 935 936 resp := new(packp.UploadPackResponse) 937 o := &FetchOptions{ 938 Depth: 1, 939 } 940 941 for _, t := range tests { 942 resp.Shallows = t.hashes 943 err = remote.updateShallow(o, resp) 944 c.Assert(err, IsNil) 945 946 shallow, err := remote.s.Shallow() 947 c.Assert(err, IsNil) 948 c.Assert(len(shallow), Equals, len(t.result)) 949 c.Assert(shallow, DeepEquals, t.result) 950 } 951} 952 953func (s *RemoteSuite) TestUseRefDeltas(c *C) { 954 url := c.MkDir() 955 _, err := PlainInit(url, true) 956 c.Assert(err, IsNil) 957 958 fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit() 959 sto := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 960 961 r := NewRemote(sto, &config.RemoteConfig{ 962 Name: DefaultRemoteName, 963 URLs: []string{url}, 964 }) 965 966 ar := packp.NewAdvRefs() 967 968 ar.Capabilities.Add(capability.OFSDelta) 969 c.Assert(r.useRefDeltas(ar), Equals, false) 970 971 ar.Capabilities.Delete(capability.OFSDelta) 972 c.Assert(r.useRefDeltas(ar), Equals, true) 973}