1package git
2
3import (
4 "bytes"
5 "log"
6 "os"
7 "os/exec"
8 "path/filepath"
9 "runtime"
10 "strings"
11 "time"
12
13 fixtures "github.com/go-git/go-git-fixtures/v4"
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/object"
17 "github.com/go-git/go-git/v5/plumbing/storer"
18 "github.com/go-git/go-git/v5/storage/filesystem"
19 "github.com/go-git/go-git/v5/storage/memory"
20
21 "github.com/ProtonMail/go-crypto/openpgp"
22 "github.com/ProtonMail/go-crypto/openpgp/armor"
23 "github.com/ProtonMail/go-crypto/openpgp/errors"
24 "github.com/go-git/go-billy/v5/memfs"
25 "github.com/go-git/go-billy/v5/util"
26 . "gopkg.in/check.v1"
27)
28
29func (s *WorktreeSuite) TestCommitEmptyOptions(c *C) {
30 fs := memfs.New()
31 r, err := Init(memory.NewStorage(), fs)
32 c.Assert(err, IsNil)
33
34 w, err := r.Worktree()
35 c.Assert(err, IsNil)
36
37 util.WriteFile(fs, "foo", []byte("foo"), 0644)
38
39 _, err = w.Add("foo")
40 c.Assert(err, IsNil)
41
42 hash, err := w.Commit("foo", &CommitOptions{})
43 c.Assert(err, IsNil)
44 c.Assert(hash.IsZero(), Equals, false)
45
46 commit, err := r.CommitObject(hash)
47 c.Assert(err, IsNil)
48 c.Assert(commit.Author.Name, Not(Equals), "")
49}
50
51func (s *WorktreeSuite) TestCommitInitial(c *C) {
52 expected := plumbing.NewHash("98c4ac7c29c913f7461eae06e024dc18e80d23a4")
53
54 fs := memfs.New()
55 storage := memory.NewStorage()
56
57 r, err := Init(storage, fs)
58 c.Assert(err, IsNil)
59
60 w, err := r.Worktree()
61 c.Assert(err, IsNil)
62
63 util.WriteFile(fs, "foo", []byte("foo"), 0644)
64
65 _, err = w.Add("foo")
66 c.Assert(err, IsNil)
67
68 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
69 c.Assert(hash, Equals, expected)
70 c.Assert(err, IsNil)
71
72 assertStorageStatus(c, r, 1, 1, 1, expected)
73}
74
75func (s *WorktreeSuite) TestNothingToCommit(c *C) {
76 expected := plumbing.NewHash("838ea833ce893e8555907e5ef224aa076f5e274a")
77
78 r, err := Init(memory.NewStorage(), memfs.New())
79 c.Assert(err, IsNil)
80
81 w, err := r.Worktree()
82 c.Assert(err, IsNil)
83
84 hash, err := w.Commit("failed empty commit\n", &CommitOptions{Author: defaultSignature()})
85 c.Assert(hash, Equals, plumbing.ZeroHash)
86 c.Assert(err, Equals, ErrEmptyCommit)
87
88 hash, err = w.Commit("enable empty commits\n", &CommitOptions{Author: defaultSignature(), AllowEmptyCommits: true})
89 c.Assert(hash, Equals, expected)
90 c.Assert(err, IsNil)
91}
92
93func (s *WorktreeSuite) TestNothingToCommitNonEmptyRepo(c *C) {
94 fs := memfs.New()
95 r, err := Init(memory.NewStorage(), fs)
96 c.Assert(err, IsNil)
97
98 w, err := r.Worktree()
99 c.Assert(err, IsNil)
100
101 err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
102 c.Assert(err, IsNil)
103
104 w.Add("foo")
105 _, err = w.Commit("previous commit\n", &CommitOptions{Author: defaultSignature()})
106 c.Assert(err, IsNil)
107
108 hash, err := w.Commit("failed empty commit\n", &CommitOptions{Author: defaultSignature()})
109 c.Assert(hash, Equals, plumbing.ZeroHash)
110 c.Assert(err, Equals, ErrEmptyCommit)
111
112 _, err = w.Commit("enable empty commits\n", &CommitOptions{Author: defaultSignature(), AllowEmptyCommits: true})
113 c.Assert(err, IsNil)
114}
115
116func (s *WorktreeSuite) TestRemoveAndCommitToMakeEmptyRepo(c *C) {
117 fs := memfs.New()
118 r, err := Init(memory.NewStorage(), fs)
119 c.Assert(err, IsNil)
120
121 w, err := r.Worktree()
122 c.Assert(err, IsNil)
123
124 err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
125 c.Assert(err, IsNil)
126
127 _, err = w.Add("foo")
128 c.Assert(err, IsNil)
129
130 _, err = w.Commit("Add in Repo\n", &CommitOptions{Author: defaultSignature()})
131 c.Assert(err, IsNil)
132
133 err = fs.Remove("foo")
134 c.Assert(err, IsNil)
135
136 _, err = w.Add("foo")
137 c.Assert(err, IsNil)
138
139 _, err = w.Commit("Remove foo\n", &CommitOptions{Author: defaultSignature()})
140 c.Assert(err, IsNil)
141}
142
143func (s *WorktreeSuite) TestCommitParent(c *C) {
144 expected := plumbing.NewHash("ef3ca05477530b37f48564be33ddd48063fc7a22")
145
146 fs := memfs.New()
147 w := &Worktree{
148 r: s.Repository,
149 Filesystem: fs,
150 }
151
152 err := w.Checkout(&CheckoutOptions{})
153 c.Assert(err, IsNil)
154
155 err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
156 c.Assert(err, IsNil)
157
158 _, err = w.Add("foo")
159 c.Assert(err, IsNil)
160
161 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
162 c.Assert(hash, Equals, expected)
163 c.Assert(err, IsNil)
164
165 assertStorageStatus(c, s.Repository, 13, 11, 10, expected)
166}
167
168func (s *WorktreeSuite) TestCommitAmendWithoutChanges(c *C) {
169 fs := memfs.New()
170 w := &Worktree{
171 r: s.Repository,
172 Filesystem: fs,
173 }
174
175 err := w.Checkout(&CheckoutOptions{})
176 c.Assert(err, IsNil)
177
178 err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
179 c.Assert(err, IsNil)
180
181 _, err = w.Add("foo")
182 c.Assert(err, IsNil)
183
184 prevHash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
185 c.Assert(err, IsNil)
186
187 amendedHash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), Amend: true})
188 c.Assert(err, IsNil)
189
190 headRef, err := w.r.Head()
191 c.Assert(err, IsNil)
192
193 c.Assert(amendedHash, Equals, headRef.Hash())
194 c.Assert(amendedHash, Equals, prevHash)
195
196 commit, err := w.r.CommitObject(headRef.Hash())
197 c.Assert(err, IsNil)
198 c.Assert(commit.Message, Equals, "foo\n")
199
200 assertStorageStatus(c, s.Repository, 13, 11, 10, amendedHash)
201}
202
203func (s *WorktreeSuite) TestCommitAmendWithChanges(c *C) {
204 fs := memfs.New()
205 w := &Worktree{
206 r: s.Repository,
207 Filesystem: fs,
208 }
209
210 err := w.Checkout(&CheckoutOptions{})
211 c.Assert(err, IsNil)
212
213 util.WriteFile(fs, "foo", []byte("foo"), 0644)
214
215 _, err = w.Add("foo")
216 c.Assert(err, IsNil)
217
218 _, err = w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
219 c.Assert(err, IsNil)
220
221 util.WriteFile(fs, "bar", []byte("bar"), 0644)
222
223 _, err = w.Add("bar")
224 c.Assert(err, IsNil)
225
226 amendedHash, err := w.Commit("bar\n", &CommitOptions{Amend: true})
227 c.Assert(err, IsNil)
228
229 headRef, err := w.r.Head()
230 c.Assert(err, IsNil)
231
232 c.Assert(amendedHash, Equals, headRef.Hash())
233
234 commit, err := w.r.CommitObject(headRef.Hash())
235 c.Assert(err, IsNil)
236 c.Assert(commit.Message, Equals, "bar\n")
237 c.Assert(commit.NumParents(), Equals, 1)
238
239 stats, err := commit.Stats()
240 c.Assert(err, IsNil)
241 c.Assert(stats, HasLen, 2)
242 c.Assert(stats[0], Equals, object.FileStat{
243 Name: "bar",
244 Addition: 1,
245 })
246 c.Assert(stats[1], Equals, object.FileStat{
247 Name: "foo",
248 Addition: 1,
249 })
250
251 assertStorageStatus(c, s.Repository, 14, 12, 11, amendedHash)
252}
253
254func (s *WorktreeSuite) TestCommitAmendNothingToCommit(c *C) {
255 fs := memfs.New()
256 w := &Worktree{
257 r: s.Repository,
258 Filesystem: fs,
259 }
260
261 err := w.Checkout(&CheckoutOptions{})
262 c.Assert(err, IsNil)
263
264 err = util.WriteFile(fs, "foo", []byte("foo"), 0644)
265 c.Assert(err, IsNil)
266
267 _, err = w.Add("foo")
268 c.Assert(err, IsNil)
269
270 prevHash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()})
271 c.Assert(err, IsNil)
272
273 _, err = w.Commit("bar\n", &CommitOptions{Author: defaultSignature(), AllowEmptyCommits: true})
274 c.Assert(err, IsNil)
275
276 amendedHash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), Amend: true})
277 c.Log(prevHash, amendedHash)
278 c.Assert(err, Equals, ErrEmptyCommit)
279 c.Assert(amendedHash, Equals, plumbing.ZeroHash)
280}
281
282func (s *WorktreeSuite) TestAddAndCommitWithSkipStatus(c *C) {
283 expected := plumbing.NewHash("375a3808ffde7f129cdd3c8c252fd0fe37cfd13b")
284
285 fs := memfs.New()
286 w := &Worktree{
287 r: s.Repository,
288 Filesystem: fs,
289 }
290
291 err := w.Checkout(&CheckoutOptions{})
292 c.Assert(err, IsNil)
293
294 util.WriteFile(fs, "LICENSE", []byte("foo"), 0644)
295 util.WriteFile(fs, "foo", []byte("foo"), 0644)
296
297 err = w.AddWithOptions(&AddOptions{
298 Path: "foo",
299 SkipStatus: true,
300 })
301 c.Assert(err, IsNil)
302
303 hash, err := w.Commit("commit foo only\n", &CommitOptions{
304 Author: defaultSignature(),
305 })
306
307 c.Assert(hash, Equals, expected)
308 c.Assert(err, IsNil)
309
310 assertStorageStatus(c, s.Repository, 13, 11, 10, expected)
311}
312
313func (s *WorktreeSuite) TestAddAndCommitWithSkipStatusPathNotModified(c *C) {
314 expected := plumbing.NewHash("375a3808ffde7f129cdd3c8c252fd0fe37cfd13b")
315 expected2 := plumbing.NewHash("8691273baf8f6ee2cccfc05e910552c04d02d472")
316
317 fs := memfs.New()
318 w := &Worktree{
319 r: s.Repository,
320 Filesystem: fs,
321 }
322
323 err := w.Checkout(&CheckoutOptions{})
324 c.Assert(err, IsNil)
325
326 util.WriteFile(fs, "foo", []byte("foo"), 0644)
327
328 status, err := w.Status()
329 c.Assert(err, IsNil)
330 foo := status.File("foo")
331 c.Assert(foo.Staging, Equals, Untracked)
332 c.Assert(foo.Worktree, Equals, Untracked)
333
334 err = w.AddWithOptions(&AddOptions{
335 Path: "foo",
336 SkipStatus: true,
337 })
338 c.Assert(err, IsNil)
339
340 status, err = w.Status()
341 c.Assert(err, IsNil)
342 foo = status.File("foo")
343 c.Assert(foo.Staging, Equals, Added)
344 c.Assert(foo.Worktree, Equals, Unmodified)
345
346 hash, err := w.Commit("commit foo only\n", &CommitOptions{All: true,
347 Author: defaultSignature(),
348 })
349 c.Assert(hash, Equals, expected)
350 c.Assert(err, IsNil)
351
352 commit1, err := w.r.CommitObject(hash)
353 c.Assert(err, IsNil)
354
355 status, err = w.Status()
356 c.Assert(err, IsNil)
357 foo = status.File("foo")
358 c.Assert(foo.Staging, Equals, Untracked)
359 c.Assert(foo.Worktree, Equals, Untracked)
360
361 assertStorageStatus(c, s.Repository, 13, 11, 10, expected)
362
363 err = w.AddWithOptions(&AddOptions{
364 Path: "foo",
365 SkipStatus: true,
366 })
367 c.Assert(err, IsNil)
368
369 status, err = w.Status()
370 c.Assert(err, IsNil)
371 foo = status.File("foo")
372 c.Assert(foo.Staging, Equals, Untracked)
373 c.Assert(foo.Worktree, Equals, Untracked)
374
375 hash, err = w.Commit("commit with no changes\n", &CommitOptions{
376 Author: defaultSignature(),
377 AllowEmptyCommits: true,
378 })
379 c.Assert(hash, Equals, expected2)
380 c.Assert(err, IsNil)
381
382 commit2, err := w.r.CommitObject(hash)
383 c.Assert(err, IsNil)
384
385 status, err = w.Status()
386 c.Assert(err, IsNil)
387 foo = status.File("foo")
388 c.Assert(foo.Staging, Equals, Untracked)
389 c.Assert(foo.Worktree, Equals, Untracked)
390
391 patch, err := commit2.Patch(commit1)
392 c.Assert(err, IsNil)
393 files := patch.FilePatches()
394 c.Assert(files, IsNil)
395
396 assertStorageStatus(c, s.Repository, 13, 11, 11, expected2)
397}
398
399func (s *WorktreeSuite) TestCommitAll(c *C) {
400 expected := plumbing.NewHash("aede6f8c9c1c7ec9ca8d287c64b8ed151276fa28")
401
402 fs := memfs.New()
403 w := &Worktree{
404 r: s.Repository,
405 Filesystem: fs,
406 }
407
408 err := w.Checkout(&CheckoutOptions{})
409 c.Assert(err, IsNil)
410
411 util.WriteFile(fs, "LICENSE", []byte("foo"), 0644)
412 util.WriteFile(fs, "foo", []byte("foo"), 0644)
413
414 hash, err := w.Commit("foo\n", &CommitOptions{
415 All: true,
416 Author: defaultSignature(),
417 })
418
419 c.Assert(hash, Equals, expected)
420 c.Assert(err, IsNil)
421
422 assertStorageStatus(c, s.Repository, 13, 11, 10, expected)
423}
424
425func (s *WorktreeSuite) TestRemoveAndCommitAll(c *C) {
426 expected := plumbing.NewHash("907cd576c6ced2ecd3dab34a72bf9cf65944b9a9")
427
428 fs := memfs.New()
429 w := &Worktree{
430 r: s.Repository,
431 Filesystem: fs,
432 }
433
434 err := w.Checkout(&CheckoutOptions{})
435 c.Assert(err, IsNil)
436
437 util.WriteFile(fs, "foo", []byte("foo"), 0644)
438 _, err = w.Add("foo")
439 c.Assert(err, IsNil)
440
441 _, errFirst := w.Commit("Add in Repo\n", &CommitOptions{
442 Author: defaultSignature(),
443 })
444 c.Assert(errFirst, IsNil)
445
446 errRemove := fs.Remove("foo")
447 c.Assert(errRemove, IsNil)
448
449 hash, errSecond := w.Commit("Remove foo\n", &CommitOptions{
450 All: true,
451 Author: defaultSignature(),
452 })
453 c.Assert(errSecond, IsNil)
454
455 c.Assert(hash, Equals, expected)
456 c.Assert(err, IsNil)
457
458 assertStorageStatus(c, s.Repository, 13, 11, 11, expected)
459}
460
461func (s *WorktreeSuite) TestCommitSign(c *C) {
462 fs := memfs.New()
463 storage := memory.NewStorage()
464
465 r, err := Init(storage, fs)
466 c.Assert(err, IsNil)
467
468 w, err := r.Worktree()
469 c.Assert(err, IsNil)
470
471 util.WriteFile(fs, "foo", []byte("foo"), 0644)
472
473 _, err = w.Add("foo")
474 c.Assert(err, IsNil)
475
476 key := commitSignKey(c, true)
477 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key})
478 c.Assert(err, IsNil)
479
480 // Verify the commit.
481 pks := new(bytes.Buffer)
482 pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil)
483 c.Assert(err, IsNil)
484
485 err = key.Serialize(pkw)
486 c.Assert(err, IsNil)
487 err = pkw.Close()
488 c.Assert(err, IsNil)
489
490 expectedCommit, err := r.CommitObject(hash)
491 c.Assert(err, IsNil)
492 actual, err := expectedCommit.Verify(pks.String())
493 c.Assert(err, IsNil)
494 c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey)
495}
496
497func (s *WorktreeSuite) TestCommitSignBadKey(c *C) {
498 fs := memfs.New()
499 storage := memory.NewStorage()
500
501 r, err := Init(storage, fs)
502 c.Assert(err, IsNil)
503
504 w, err := r.Worktree()
505 c.Assert(err, IsNil)
506
507 util.WriteFile(fs, "foo", []byte("foo"), 0644)
508
509 _, err = w.Add("foo")
510 c.Assert(err, IsNil)
511
512 key := commitSignKey(c, false)
513 _, err = w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key})
514 c.Assert(err, Equals, errors.InvalidArgumentError("signing key is encrypted"))
515}
516
517func (s *WorktreeSuite) TestCommitTreeSort(c *C) {
518 fs := s.TemporalFilesystem(c)
519
520 st := filesystem.NewStorage(fs, cache.NewObjectLRUDefault())
521 _, err := Init(st, nil)
522 c.Assert(err, IsNil)
523
524 r, _ := Clone(memory.NewStorage(), memfs.New(), &CloneOptions{
525 URL: fs.Root(),
526 })
527
528 w, err := r.Worktree()
529 c.Assert(err, IsNil)
530
531 mfs := w.Filesystem
532
533 err = mfs.MkdirAll("delta", 0755)
534 c.Assert(err, IsNil)
535
536 for _, p := range []string{"delta_last", "Gamma", "delta/middle", "Beta", "delta-first", "alpha"} {
537 util.WriteFile(mfs, p, []byte("foo"), 0644)
538 _, err = w.Add(p)
539 c.Assert(err, IsNil)
540 }
541
542 _, err = w.Commit("foo\n", &CommitOptions{
543 All: true,
544 Author: defaultSignature(),
545 })
546 c.Assert(err, IsNil)
547
548 err = r.Push(&PushOptions{})
549 c.Assert(err, IsNil)
550
551 cmd := exec.Command("git", "fsck")
552 cmd.Dir = fs.Root()
553 cmd.Env = os.Environ()
554 buf := &bytes.Buffer{}
555 cmd.Stderr = buf
556 cmd.Stdout = buf
557
558 err = cmd.Run()
559
560 c.Assert(err, IsNil, Commentf("%s", buf.Bytes()))
561}
562
563// https://github.com/go-git/go-git/pull/224
564func (s *WorktreeSuite) TestJustStoreObjectsNotAlreadyStored(c *C) {
565 fs := s.TemporalFilesystem(c)
566
567 fsDotgit, err := fs.Chroot(".git") // real fs to get modified timestamps
568 c.Assert(err, IsNil)
569 storage := filesystem.NewStorage(fsDotgit, cache.NewObjectLRUDefault())
570
571 r, err := Init(storage, fs)
572 c.Assert(err, IsNil)
573
574 w, err := r.Worktree()
575 c.Assert(err, IsNil)
576
577 // Step 1: Write LICENSE
578 util.WriteFile(fs, "LICENSE", []byte("license"), 0644)
579 hLicense, err := w.Add("LICENSE")
580 c.Assert(err, IsNil)
581 c.Assert(hLicense, Equals, plumbing.NewHash("0484eba0d41636ba71fa612c78559cd6c3006cde"))
582
583 hash, err := w.Commit("commit 1\n", &CommitOptions{
584 All: true,
585 Author: defaultSignature(),
586 })
587 c.Assert(err, IsNil)
588 c.Assert(hash, Equals, plumbing.NewHash("7a7faee4630d2664a6869677cc8ab614f3fd4a18"))
589
590 infoLicense, err := fsDotgit.Stat(filepath.Join("objects", "04", "84eba0d41636ba71fa612c78559cd6c3006cde"))
591 c.Assert(err, IsNil) // checking objects file exists
592
593 // Step 2: Write foo.
594 time.Sleep(5 * time.Millisecond) // uncool, but we need to get different timestamps...
595 util.WriteFile(fs, "foo", []byte("foo"), 0644)
596 hFoo, err := w.Add("foo")
597 c.Assert(err, IsNil)
598 c.Assert(hFoo, Equals, plumbing.NewHash("19102815663d23f8b75a47e7a01965dcdc96468c"))
599
600 hash, err = w.Commit("commit 2\n", &CommitOptions{
601 All: true,
602 Author: defaultSignature(),
603 })
604 c.Assert(err, IsNil)
605 c.Assert(hash, Equals, plumbing.NewHash("97c0c5177e6ac57d10e8ea0017f2d39b91e2b364"))
606
607 // Step 3: Check
608 // There is no need to overwrite the object of LICENSE, because its content
609 // was not changed. Just a write on the object of foo is required. This behaviour
610 // is fixed by #224 and tested by comparing the timestamps of the stored objects.
611 infoFoo, err := fsDotgit.Stat(filepath.Join("objects", "19", "102815663d23f8b75a47e7a01965dcdc96468c"))
612 c.Assert(err, IsNil) // checking objects file exists
613 c.Assert(infoLicense.ModTime().Before(infoFoo.ModTime()), Equals, true) // object of foo has another/greaterThan timestamp than LICENSE
614
615 infoLicenseSecond, err := fsDotgit.Stat(filepath.Join("objects", "04", "84eba0d41636ba71fa612c78559cd6c3006cde"))
616 c.Assert(err, IsNil)
617
618 log.Printf("comparing mod time: %v == %v on %v (%v)", infoLicenseSecond.ModTime(), infoLicense.ModTime(), runtime.GOOS, runtime.GOARCH)
619 c.Assert(infoLicenseSecond.ModTime(), Equals, infoLicense.ModTime()) // object of LICENSE should have the same timestamp because no additional write operation was performed
620}
621
622func (s *WorktreeSuite) TestCommitInvalidCharactersInAuthorInfos(c *C) {
623 f := fixtures.Basic().One()
624 s.Repository = s.NewRepositoryWithEmptyWorktree(f)
625
626 expected := plumbing.NewHash("e8eecef2524c3a37cf0f0996603162f81e0373f1")
627
628 fs := memfs.New()
629 storage := memory.NewStorage()
630
631 r, err := Init(storage, fs)
632 c.Assert(err, IsNil)
633
634 w, err := r.Worktree()
635 c.Assert(err, IsNil)
636
637 util.WriteFile(fs, "foo", []byte("foo"), 0644)
638
639 _, err = w.Add("foo")
640 c.Assert(err, IsNil)
641
642 hash, err := w.Commit("foo\n", &CommitOptions{Author: invalidSignature()})
643 c.Assert(hash, Equals, expected)
644 c.Assert(err, IsNil)
645
646 assertStorageStatus(c, r, 1, 1, 1, expected)
647
648 // Check HEAD commit contains author informations with '<', '>' and '\n' stripped
649 lr, err := r.Log(&LogOptions{})
650 c.Assert(err, IsNil)
651
652 commit, err := lr.Next()
653 c.Assert(err, IsNil)
654
655 c.Assert(commit.Author.Name, Equals, "foo bad")
656 c.Assert(commit.Author.Email, Equals, "badfoo@foo.foo")
657
658}
659
660func assertStorageStatus(
661 c *C, r *Repository,
662 treesCount, blobCount, commitCount int, head plumbing.Hash,
663) {
664 trees, err := r.Storer.IterEncodedObjects(plumbing.TreeObject)
665 c.Assert(err, IsNil)
666 blobs, err := r.Storer.IterEncodedObjects(plumbing.BlobObject)
667 c.Assert(err, IsNil)
668 commits, err := r.Storer.IterEncodedObjects(plumbing.CommitObject)
669 c.Assert(err, IsNil)
670
671 c.Assert(lenIterEncodedObjects(trees), Equals, treesCount)
672 c.Assert(lenIterEncodedObjects(blobs), Equals, blobCount)
673 c.Assert(lenIterEncodedObjects(commits), Equals, commitCount)
674
675 ref, err := r.Head()
676 c.Assert(err, IsNil)
677 c.Assert(ref.Hash(), Equals, head)
678}
679
680func lenIterEncodedObjects(iter storer.EncodedObjectIter) int {
681 count := 0
682 iter.ForEach(func(plumbing.EncodedObject) error {
683 count++
684 return nil
685 })
686
687 return count
688}
689
690func defaultSignature() *object.Signature {
691 when, _ := time.Parse(object.DateFormat, "Thu May 04 00:03:43 2017 +0200")
692 return &object.Signature{
693 Name: "foo",
694 Email: "foo@foo.foo",
695 When: when,
696 }
697}
698
699func invalidSignature() *object.Signature {
700 when, _ := time.Parse(object.DateFormat, "Thu May 04 00:03:43 2017 +0200")
701 return &object.Signature{
702 Name: "foo <bad>\n",
703 Email: "<bad>\nfoo@foo.foo",
704 When: when,
705 }
706}
707
708func commitSignKey(c *C, decrypt bool) *openpgp.Entity {
709 s := strings.NewReader(armoredKeyRing)
710 es, err := openpgp.ReadArmoredKeyRing(s)
711 c.Assert(err, IsNil)
712
713 c.Assert(es, HasLen, 1)
714 c.Assert(es[0].Identities, HasLen, 1)
715 _, ok := es[0].Identities["foo bar <foo@foo.foo>"]
716 c.Assert(ok, Equals, true)
717
718 key := es[0]
719 if decrypt {
720 err = key.PrivateKey.Decrypt([]byte(keyPassphrase))
721 c.Assert(err, IsNil)
722 }
723
724 return key
725}
726
727const armoredKeyRing = `
728-----BEGIN PGP PRIVATE KEY BLOCK-----
729
730lQdGBFt89QIBEAC8du0Purt9yeFuLlBYHcexnZvcbaci2pY+Ejn1VnxM7caFxRX/
731b2weZi9E6+I0F+K/hKIaidPdcbK92UCL0Vp6F3izjqategZ7o44vlK/HfWFME4wv
732sou6lnig9ovA73HRyzngi3CmqWxSdg8lL0kIJLNzlvCFEd4Z34BnEkagklQJRymo
7330WnmLJjSnZFT5Nk7q5jrcR7ApbD98cakvgivDlUBPJCk2JFPWheCkouWPHMvLXQz
734bZXW5RFz4lJsMUWa/S3ofvIOnjG5Etnil3IA4uksS8fSDkGus998mBvUwzqX7xBh
735dK17ZEbxDdO4PuVJDkjvq618rMu8FVk5yVd59rUketSnGrehd/+vdh6qtgQC4tu1
736RldbUVAuKZGg79H61nWnvrDZmbw4eoqCEuv1+aZsM9ElSC5Ps2J0rtpHRyBndKn+
7378Jlc/KTH04/O+FAhEv0IgMTFEm3iAq8udBhRBgu6Y4gJyn4tqy6+6ZjPUNos8GOG
738+ZJPdrgHHHfQged1ygeceN6W2AwQRet/B3/rieHf2V93uHJy/DjYUEuBhPm9nxqi
739R6ILUr97Sj2EsvLyfQO9pFpIctoNKEJmDx/C9tkFMNNlQhpsBitSdR2/wancw9ND
740iWV/J9roUdC0qns7eNSbiFe3Len8Xir7srnjAFgbGvOu9jDBUuiKGT5F3wARAQAB
741/gcDAl+0SktmjrUW8uwpvru6GeIeo5kc4rXuD7iIxH6nDl3nmjZMX7qWvp+pRTHH
7420hEDH44899PDvzclBN3ouehfFUbJ+DBy8umBiLqF8Mu2PrKjdmyv3BvnbTkqPM3m
7432Su7WmUDBhG00X07lfl8fTpZJG80onEGzGynryP/xVm4ymzoHyYGksntXLYr2HJ5
744aV6L7sL2/STsaaOVHoa/oEmVBo1+NRsTxRRUcFVLs3g0OIi6ZCeSevBdavMwf9Iv
745b5Bs/e0+GLpP71XzFpdrGcL6oGjZH/dgdeypzbGA+FHtQJqynN3qEE9eCc9cfTGL
7462zN2OtnMA28NtPVN4SnSxQIDvycWx68NZjfwLOK+gswfKpimp+6xMWSnNIRDyU9M
747w0hdNPMK9JAxm/MlnkR7x6ysX/8vrVVFl9gWOmxzJ5L4kvfMsHcV5ZFRP8OnVA6a
748NFBWIBGXF1uQC4qrXup/xKyWJOoH++cMo2cjPT3+3oifZgdBydVfHXjS9aQ/S3Sa
749A6henWyx/qeBGPVRuXWdXIOKDboOPK8JwQaGd6yazKkH9c5tDohmQHzZ6ho0gyAt
750dh+g9ZyiZVpjc6excfK/DP/RdUOYKw3Ur9652hKephvYZzHvPjTbqVkhS7JjZkVY
751rukQ64d5T0pE1B4y+If4hLFXMNQtfo0TIsATNA69jop+KFnJpLzAB+Ee33EA/HUl
752YC5EJCJaXt6kdtYFac0HvVWiz5ZuMhdtzpJfvOe+Olp/xR9nIPW3XZojQoHIZKwu
753gXeZeVMvfeoq+ymKAKNH5Np4WaUDF7Wh9VLl045jGyF5viyy61ivC0eyAzp5W1uy
754gJBZwafVma5MhmZUS2dFs0hBwBrKRzZZhN65VvfSYw6CnXp83ryUjReDvrLmqZDM
755FNpSMDKRk1+k9Wwi3m+fzLAvlxoHscJ5Any7ApsvBRbyehP8MAAG7UV3jImugTLi
756yN6FKVwziQXiC4/97oKbA1YYNjTT7Qw9gWTXvLRspn4f9997brcA9dm0M0seTjLa
757lc5hTJwJQdvPPI2klf+YgPvsD6nrP1moeWBb8irICqG1/BoE0JHPS+bqJ1J+m1iV
758kRV/+4pV2bLlXKqg1LEvqANW+1P1eM2nbbVB7EQn8ZOPIKMoCLoC1QWUPNfnemsW
759U5ynAbhsbm16PDJql0ApEgUCEDfsXTu1ui6SIO3bs/gWyD9HEmnfaYMYDKF+j+0r
760jXd4GnCxb+Yu3wV5WyewOHouzC+++h/3WcDLkOYZ9pcIbA86qT+v6b9MuTAU0D3c
761wlDv8r5J59zOcXl4HpMb2BY5F9dZn8hjgeVJRhJdij9x1TQ8qlVasSi4Eq8SiPmZ
762PZz33Pk6yn2caQ6wd47A79LXCbFQqJqA5aA6oS4DOpENGS5fh7WUZq/MTcmm9GsG
763w2gHxocASK9RCUYgZFWVYgLDuviMMWvc/2TJcTMxdF0Amu3erYAD90smFs0g/6fZ
7644pRLnKFuifwAMGMOx7jbW5tmOaSPx6XkuYvkDJeLMHoN3z/8bZEG5VpayypwFGyV
765bk/YIUWg/KM/43juDPdTvab9tZzYIjxC6on7dtYIAGjZis97XZou3KYKTaMe1VY6
766IhrnVzJ0JAHpd1prf9NUz96e1vjGdn3I61JgjNp5sWklIJEZzvaD28Eovf/LH1BO
767gYFFCvsWXaRoPHNQ5a9m7CROkLeHUFgRu5uriqHxxQHgogDznc8/3fnvDAHNpNb6
768Jnk4zaeVR3tTyIjiNM+wxUFPDNFpJWmQbSDCcPVYTbpznzVRnhqrw7q0FWZvbyBi
769YXIgPGZvb0Bmb28uZm9vPokCVAQTAQgAPgIbAwULCQgHAgYVCAkKCwIEFgIDAQIe
770AQIXgBYhBJOhf/AeVDKFRgh8jgKTlUAu/M1TBQJbfPU4BQkSzAM2AAoJEAKTlUAu
771/M1TVTIQALA6ocNc2fXz1loLykMxlfnX/XxiyNDOUPDZkrZtscqqWPYaWvJK3OiD
77232bdVEbftnAiFvJYkinrCXLEmwwf5wyOxKFmCHwwKhH0UYt60yF4WwlOVNstGSAy
773RkPMEEmVfMXS9K1nzKv/9A5YsqMQob7sN5CMN66Vrm0RKSvOF/NhhM9v8fC0QSU2
774GZNO0tnRfaS4wMnFr5L4FuDST+14F5sJT7ZEJz7HfbxXKLvvWbvqLlCYHJOdz56s
775X/eKde8eT9/LSzcmgsd7rGS2np5901kubww5jllUl1CFnk3Mdg9FTJl5u9Epuhnn
776823Jpdy1ZNbyLqZ266Z/q2HepDA7P/GqIXgWdHjwG2y1YAC4JIkA4RBbesQwqAXs
7776cX5gqRFRl5iDGEP5zclS0y5mWi/J8bLYxMYfqxs9EZtHd9DumWISi87804TEzYa
778WDijMlW7PR8QRW0vdmtYOhJZOlTnomLQx2v27iqpVXRh12J1aYVBFC+IvG1vhCf9
779FL3LzAHHEGlIoDaKJMd+Wg/Lm/f1PqqQx3lWIh9hhKh5Qx6hcuJH669JOWuEdxfo
7801so50aItG+tdDKqXflmOi7grrUURchYYKteaW2fC2SQgzDClprALI7aj9s/lDrEN
781CgLH6twOqdSFWqB/4ASDMsNeLeKX3WOYKYYMlE01cj3T1m6dpRUO
782=gIM9
783-----END PGP PRIVATE KEY BLOCK-----
784`
785
786const keyPassphrase = "abcdef0123456789"