Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 39ecae5

Browse files
committed
remote: push, update remote refs on push
1 parent 2d10f10 commit 39ecae5

File tree

4 files changed

+152
-171
lines changed

4 files changed

+152
-171
lines changed

common_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,14 @@ func (s *SuiteCommon) TestCountLines(c *C) {
169169
c.Assert(o, Equals, t.e, Commentf("subtest %d, input=%q", i, t.i))
170170
}
171171
}
172+
173+
func AssertReferences(c *C, r *Repository, expected map[string]string) {
174+
for name, target := range expected {
175+
expected := plumbing.NewReferenceFromStrings(name, target)
176+
177+
obtained, err := r.Reference(expected.Name(), true)
178+
c.Assert(err, IsNil)
179+
180+
c.Assert(obtained, DeepEquals, expected)
181+
}
182+
}

remote.go

+42-15
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,10 @@ func (r *Remote) String() string {
4848
return fmt.Sprintf("%s\t%s (fetch)\n%[1]s\t%[3]s (push)", r.c.Name, fetch, push)
4949
}
5050

51-
// Fetch fetches references from the remote to the local repository.
52-
// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
53-
// no changes to be fetched and no local references to update, or an error.
54-
func (r *Remote) Fetch(o *FetchOptions) error {
55-
_, err := r.fetch(o)
56-
return err
57-
}
58-
5951
// Push performs a push to the remote. Returns NoErrAlreadyUpToDate if the
6052
// remote was already up-to-date.
61-
func (r *Remote) Push(o *PushOptions) (err error) {
53+
func (r *Remote) Push(o *PushOptions) error {
6254
// TODO: Sideband support
63-
64-
if o.RemoteName == "" {
65-
o.RemoteName = r.c.Name
66-
}
67-
6855
if err := o.Validate(); err != nil {
6956
return err
7057
}
@@ -141,7 +128,47 @@ func (r *Remote) Push(o *PushOptions) (err error) {
141128
return err
142129
}
143130

144-
return rs.Error()
131+
if err = rs.Error(); err != nil {
132+
return err
133+
}
134+
135+
return r.updateRemoteReferenceStorage(req, rs)
136+
}
137+
138+
func (r *Remote) updateRemoteReferenceStorage(
139+
req *packp.ReferenceUpdateRequest,
140+
result *packp.ReportStatus,
141+
) error {
142+
143+
for _, spec := range r.c.Fetch {
144+
for _, c := range req.Commands {
145+
if !spec.Match(c.Name) {
146+
continue
147+
}
148+
149+
local := spec.Dst(c.Name)
150+
ref := plumbing.NewHashReference(local, c.New)
151+
switch c.Action() {
152+
case packp.Create, packp.Update:
153+
if err := r.s.SetReference(ref); err != nil {
154+
return err
155+
}
156+
case packp.Delete:
157+
if err := r.s.RemoveReference(local); err != nil {
158+
return err
159+
}
160+
}
161+
}
162+
}
163+
164+
return nil
165+
}
166+
167+
// Fetch fetches references from the remote to the local repository.
168+
// no changes to be fetched and no local references to update, or an error.
169+
func (r *Remote) Fetch(o *FetchOptions) error {
170+
_, err := r.fetch(o)
171+
return err
145172
}
146173

147174
func (r *Remote) fetch(o *FetchOptions) (storer.ReferenceStorer, error) {

remote_test.go

+75-115
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"io"
66
"io/ioutil"
77
"os"
8-
"path/filepath"
9-
"strings"
108

119
"github.com/src-d/go-git-fixtures"
1210
"gopkg.in/src-d/go-git.v4/config"
@@ -289,13 +287,14 @@ func (s *RemoteSuite) TestString(c *C) {
289287
}
290288

291289
func (s *RemoteSuite) TestPushToEmptyRepository(c *C) {
290+
url := c.MkDir()
291+
server, err := PlainInit(url, true)
292+
c.Assert(err, IsNil)
293+
292294
srcFs := fixtures.Basic().One().DotGit()
293295
sto, err := filesystem.NewStorage(srcFs)
294296
c.Assert(err, IsNil)
295297

296-
dstFs := fixtures.ByTag("empty").One().DotGit()
297-
url := dstFs.Root()
298-
299298
r := newRemote(sto, &config.RemoteConfig{
300299
Name: DefaultRemoteName,
301300
URL: url,
@@ -307,140 +306,117 @@ func (s *RemoteSuite) TestPushToEmptyRepository(c *C) {
307306
})
308307
c.Assert(err, IsNil)
309308

310-
dstSto, err := filesystem.NewStorage(dstFs)
311-
c.Assert(err, IsNil)
312-
dstRepo, err := Open(dstSto, nil)
309+
iter, err := r.s.IterReferences()
313310
c.Assert(err, IsNil)
314311

315-
iter, err := sto.IterReferences()
316-
c.Assert(err, IsNil)
317-
err = iter.ForEach(func(ref *plumbing.Reference) error {
312+
expected := make(map[string]string)
313+
iter.ForEach(func(ref *plumbing.Reference) error {
318314
if !ref.IsBranch() {
319315
return nil
320316
}
321317

322-
dstRef, err := dstRepo.Reference(ref.Name(), true)
323-
c.Assert(err, IsNil, Commentf("ref: %s", ref.String()))
324-
c.Assert(dstRef, DeepEquals, ref)
325-
318+
expected[ref.Name().String()] = ref.Hash().String()
326319
return nil
327320
})
328321
c.Assert(err, IsNil)
322+
323+
AssertReferences(c, server, expected)
324+
329325
}
330326

331327
func (s *RemoteSuite) TestPushTags(c *C) {
332-
srcFs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit()
333-
sto, err := filesystem.NewStorage(srcFs)
328+
url := c.MkDir()
329+
server, err := PlainInit(url, true)
334330
c.Assert(err, IsNil)
335331

336-
dstFs := fixtures.ByTag("empty").One().DotGit()
337-
url := dstFs.Root()
332+
fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit()
333+
sto, err := filesystem.NewStorage(fs)
334+
c.Assert(err, IsNil)
338335

339336
r := newRemote(sto, &config.RemoteConfig{
340337
Name: DefaultRemoteName,
341338
URL: url,
342339
})
343340

344-
rs := config.RefSpec("refs/tags/*:refs/tags/*")
345341
err = r.Push(&PushOptions{
346-
RefSpecs: []config.RefSpec{rs},
342+
RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"},
347343
})
348344
c.Assert(err, IsNil)
349345

350-
dstSto, err := filesystem.NewStorage(dstFs)
351-
c.Assert(err, IsNil)
352-
dstRepo, err := Open(dstSto, nil)
353-
c.Assert(err, IsNil)
354-
355-
ref, err := dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/lightweight-tag"))
356-
c.Assert(err, IsNil)
357-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/lightweight-tag", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"))
358-
359-
ref, err = dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/annotated-tag"))
360-
c.Assert(err, IsNil)
361-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/annotated-tag", "b742a2a9fa0afcfa9a6fad080980fbc26b007c69"))
362-
363-
ref, err = dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/commit-tag"))
364-
c.Assert(err, IsNil)
365-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/commit-tag", "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc"))
366-
367-
ref, err = dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/blob-tag"))
368-
c.Assert(err, IsNil)
369-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/blob-tag", "fe6cb94756faa81e5ed9240f9191b833db5f40ae"))
370-
371-
ref, err = dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/tree-tag"))
372-
c.Assert(err, IsNil)
373-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/tree-tag", "152175bf7e5580299fa1f0ba41ef6474cc043b70"))
346+
AssertReferences(c, server, map[string]string{
347+
"refs/tags/lightweight-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
348+
"refs/tags/annotated-tag": "b742a2a9fa0afcfa9a6fad080980fbc26b007c69",
349+
"refs/tags/commit-tag": "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc",
350+
"refs/tags/blob-tag": "fe6cb94756faa81e5ed9240f9191b833db5f40ae",
351+
"refs/tags/tree-tag": "152175bf7e5580299fa1f0ba41ef6474cc043b70",
352+
})
374353
}
375354

376355
func (s *RemoteSuite) TestPushNoErrAlreadyUpToDate(c *C) {
377-
f := fixtures.Basic().One()
378-
sto, err := filesystem.NewStorage(f.DotGit())
356+
fs := fixtures.Basic().One().DotGit()
357+
sto, err := filesystem.NewStorage(fs)
379358
c.Assert(err, IsNil)
380-
url := f.DotGit().Root()
359+
381360
r := newRemote(sto, &config.RemoteConfig{
382361
Name: DefaultRemoteName,
383-
URL: url,
362+
URL: fs.Root(),
384363
})
385364

386-
rs := config.RefSpec("refs/heads/*:refs/heads/*")
387365
err = r.Push(&PushOptions{
388-
RefSpecs: []config.RefSpec{rs},
366+
RefSpecs: []config.RefSpec{"refs/heads/*:refs/heads/*"},
389367
})
390368
c.Assert(err, Equals, NoErrAlreadyUpToDate)
391369
}
392370

393371
func (s *RemoteSuite) TestPushDeleteReference(c *C) {
394-
f := fixtures.Basic().One()
395-
sto, err := filesystem.NewStorage(f.DotGit())
372+
fs := fixtures.Basic().One().DotGit()
373+
sto, err := filesystem.NewStorage(fs)
396374
c.Assert(err, IsNil)
397375

398-
dstFs := f.DotGit()
399-
dstSto, err := filesystem.NewStorage(dstFs)
376+
r, err := PlainClone(c.MkDir(), true, &CloneOptions{
377+
URL: fs.Root(),
378+
})
400379
c.Assert(err, IsNil)
401-
prepareRepo(c, dstFs.Root())
402380

403-
url := dstFs.Root()
404-
r := newRemote(sto, &config.RemoteConfig{
405-
Name: DefaultRemoteName,
406-
URL: url,
407-
})
381+
remote, err := r.Remote(DefaultRemoteName)
382+
c.Assert(err, IsNil)
408383

409-
rs := config.RefSpec(":refs/heads/branch")
410-
err = r.Push(&PushOptions{
411-
RefSpecs: []config.RefSpec{rs},
384+
err = remote.Push(&PushOptions{
385+
RefSpecs: []config.RefSpec{":refs/heads/branch"},
412386
})
413387
c.Assert(err, IsNil)
414388

415-
_, err = dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
389+
_, err = sto.Reference(plumbing.ReferenceName("refs/heads/branch"))
390+
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
391+
392+
_, err = r.Storer.Reference(plumbing.ReferenceName("refs/heads/branch"))
416393
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
417394
}
418395

419396
func (s *RemoteSuite) TestPushRejectNonFastForward(c *C) {
420-
f := fixtures.Basic().One()
421-
sto, err := filesystem.NewStorage(f.DotGit())
397+
fs := fixtures.Basic().One().DotGit()
398+
server, err := filesystem.NewStorage(fs)
422399
c.Assert(err, IsNil)
423400

424-
dstFs := f.DotGit()
425-
dstSto, err := filesystem.NewStorage(dstFs)
401+
r, err := PlainClone(c.MkDir(), true, &CloneOptions{
402+
URL: fs.Root(),
403+
})
426404
c.Assert(err, IsNil)
427405

428-
url := dstFs.Root()
429-
r := newRemote(sto, &config.RemoteConfig{
430-
Name: DefaultRemoteName,
431-
URL: url,
432-
})
406+
remote, err := r.Remote(DefaultRemoteName)
407+
c.Assert(err, IsNil)
433408

434-
oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
409+
branch := plumbing.ReferenceName("refs/heads/branch")
410+
oldRef, err := server.Reference(branch)
435411
c.Assert(err, IsNil)
436412
c.Assert(oldRef, NotNil)
437413

438-
err = r.Push(&PushOptions{RefSpecs: []config.RefSpec{
439-
config.RefSpec("refs/heads/master:refs/heads/branch"),
414+
err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{
415+
"refs/heads/master:refs/heads/branch",
440416
}})
441417
c.Assert(err, ErrorMatches, "non-fast-forward update: refs/heads/branch")
442418

443-
newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
419+
newRef, err := server.Reference(branch)
444420
c.Assert(err, IsNil)
445421
c.Assert(newRef, DeepEquals, oldRef)
446422
}
@@ -475,32 +451,35 @@ func (s *RemoteSuite) TestPushForce(c *C) {
475451
}
476452

477453
func (s *RemoteSuite) TestPushNewReference(c *C) {
478-
f := fixtures.Basic().One()
479-
sto, err := filesystem.NewStorage(f.DotGit())
480-
c.Assert(err, IsNil)
454+
fs := fixtures.Basic().One().DotGit()
455+
url := c.MkDir()
456+
server, err := PlainClone(url, true, &CloneOptions{
457+
URL: fs.Root(),
458+
})
481459

482-
dstFs := f.DotGit()
483-
dstSto, err := filesystem.NewStorage(dstFs)
460+
r, err := PlainClone(c.MkDir(), true, &CloneOptions{
461+
URL: url,
462+
})
484463
c.Assert(err, IsNil)
485464

486-
url := dstFs.Root()
487-
r := newRemote(sto, &config.RemoteConfig{
488-
Name: DefaultRemoteName,
489-
URL: url,
490-
})
465+
remote, err := r.Remote(DefaultRemoteName)
466+
c.Assert(err, IsNil)
491467

492-
oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
468+
ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true)
493469
c.Assert(err, IsNil)
494-
c.Assert(oldRef, NotNil)
495470

496-
err = r.Push(&PushOptions{RefSpecs: []config.RefSpec{
497-
config.RefSpec("refs/heads/branch:refs/heads/branch2"),
471+
err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{
472+
"refs/heads/master:refs/heads/branch2",
498473
}})
499474
c.Assert(err, IsNil)
500475

501-
newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch2"))
502-
c.Assert(err, IsNil)
503-
c.Assert(newRef.Hash(), Equals, oldRef.Hash())
476+
AssertReferences(c, server, map[string]string{
477+
"refs/heads/branch2": ref.Hash().String(),
478+
})
479+
480+
AssertReferences(c, r, map[string]string{
481+
"refs/remotes/origin/branch2": ref.Hash().String(),
482+
})
504483
}
505484

506485
func (s *RemoteSuite) TestPushInvalidEndpoint(c *C) {
@@ -516,7 +495,7 @@ func (s *RemoteSuite) TestPushNonExistentEndpoint(c *C) {
516495
}
517496

518497
func (s *RemoteSuite) TestPushInvalidSchemaEndpoint(c *C) {
519-
r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "qux://foo"})
498+
r := newRemote(nil, &config.RemoteConfig{Name: "origin", URL: "qux://foo"})
520499
err := r.Push(&PushOptions{})
521500
c.Assert(err, ErrorMatches, ".*unsupported scheme.*")
522501
}
@@ -571,22 +550,3 @@ func (s *RemoteSuite) TestGetHaves(c *C) {
571550
c.Assert(err, IsNil)
572551
c.Assert(l, HasLen, 2)
573552
}
574-
575-
const bareConfig = `[core]
576-
repositoryformatversion = 0
577-
filemode = true
578-
bare = true`
579-
580-
func prepareRepo(c *C, path string) {
581-
// git-receive-pack refuses to update refs/heads/master on non-bare repo
582-
// so we ensure bare repo config.
583-
config := filepath.Join(path, "config")
584-
if _, err := os.Stat(config); err == nil {
585-
f, err := os.OpenFile(config, os.O_TRUNC|os.O_WRONLY, 0)
586-
c.Assert(err, IsNil)
587-
content := strings.NewReader(bareConfig)
588-
_, err = io.Copy(f, content)
589-
c.Assert(err, IsNil)
590-
c.Assert(f.Close(), IsNil)
591-
}
592-
}

0 commit comments

Comments
 (0)