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