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