fork of go-git with some jj specific features
at v4.7.1 11 kB view raw
1package git 2 3import ( 4 "bytes" 5 "io/ioutil" 6 "os" 7 "os/exec" 8 "strings" 9 "time" 10 11 "gopkg.in/src-d/go-git.v4/plumbing" 12 "gopkg.in/src-d/go-git.v4/plumbing/cache" 13 "gopkg.in/src-d/go-git.v4/plumbing/object" 14 "gopkg.in/src-d/go-git.v4/plumbing/storer" 15 "gopkg.in/src-d/go-git.v4/storage/filesystem" 16 "gopkg.in/src-d/go-git.v4/storage/memory" 17 18 "golang.org/x/crypto/openpgp" 19 "golang.org/x/crypto/openpgp/armor" 20 "golang.org/x/crypto/openpgp/errors" 21 . "gopkg.in/check.v1" 22 "gopkg.in/src-d/go-billy.v4/memfs" 23 "gopkg.in/src-d/go-billy.v4/osfs" 24 "gopkg.in/src-d/go-billy.v4/util" 25) 26 27func (s *WorktreeSuite) TestCommitInvalidOptions(c *C) { 28 r, err := Init(memory.NewStorage(), memfs.New()) 29 c.Assert(err, IsNil) 30 31 w, err := r.Worktree() 32 c.Assert(err, IsNil) 33 34 hash, err := w.Commit("", &CommitOptions{}) 35 c.Assert(err, Equals, ErrMissingAuthor) 36 c.Assert(hash.IsZero(), Equals, true) 37} 38 39func (s *WorktreeSuite) TestCommitInitial(c *C) { 40 expected := plumbing.NewHash("98c4ac7c29c913f7461eae06e024dc18e80d23a4") 41 42 fs := memfs.New() 43 storage := memory.NewStorage() 44 45 r, err := Init(storage, fs) 46 c.Assert(err, IsNil) 47 48 w, err := r.Worktree() 49 c.Assert(err, IsNil) 50 51 util.WriteFile(fs, "foo", []byte("foo"), 0644) 52 53 _, err = w.Add("foo") 54 c.Assert(err, IsNil) 55 56 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()}) 57 c.Assert(hash, Equals, expected) 58 c.Assert(err, IsNil) 59 60 assertStorageStatus(c, r, 1, 1, 1, expected) 61} 62 63func (s *WorktreeSuite) TestCommitParent(c *C) { 64 expected := plumbing.NewHash("ef3ca05477530b37f48564be33ddd48063fc7a22") 65 66 fs := memfs.New() 67 w := &Worktree{ 68 r: s.Repository, 69 Filesystem: fs, 70 } 71 72 err := w.Checkout(&CheckoutOptions{}) 73 c.Assert(err, IsNil) 74 75 util.WriteFile(fs, "foo", []byte("foo"), 0644) 76 77 _, err = w.Add("foo") 78 c.Assert(err, IsNil) 79 80 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()}) 81 c.Assert(hash, Equals, expected) 82 c.Assert(err, IsNil) 83 84 assertStorageStatus(c, s.Repository, 13, 11, 10, expected) 85} 86 87func (s *WorktreeSuite) TestCommitAll(c *C) { 88 expected := plumbing.NewHash("aede6f8c9c1c7ec9ca8d287c64b8ed151276fa28") 89 90 fs := memfs.New() 91 w := &Worktree{ 92 r: s.Repository, 93 Filesystem: fs, 94 } 95 96 err := w.Checkout(&CheckoutOptions{}) 97 c.Assert(err, IsNil) 98 99 util.WriteFile(fs, "LICENSE", []byte("foo"), 0644) 100 util.WriteFile(fs, "foo", []byte("foo"), 0644) 101 102 hash, err := w.Commit("foo\n", &CommitOptions{ 103 All: true, 104 Author: defaultSignature(), 105 }) 106 107 c.Assert(hash, Equals, expected) 108 c.Assert(err, IsNil) 109 110 assertStorageStatus(c, s.Repository, 13, 11, 10, expected) 111} 112 113func (s *WorktreeSuite) TestRemoveAndCommitAll(c *C) { 114 expected := plumbing.NewHash("907cd576c6ced2ecd3dab34a72bf9cf65944b9a9") 115 116 fs := memfs.New() 117 w := &Worktree{ 118 r: s.Repository, 119 Filesystem: fs, 120 } 121 122 err := w.Checkout(&CheckoutOptions{}) 123 c.Assert(err, IsNil) 124 125 util.WriteFile(fs, "foo", []byte("foo"), 0644) 126 _, err = w.Add("foo") 127 c.Assert(err, IsNil) 128 129 _, errFirst := w.Commit("Add in Repo\n", &CommitOptions{ 130 Author: defaultSignature(), 131 }) 132 c.Assert(errFirst, IsNil) 133 134 errRemove := fs.Remove("foo") 135 c.Assert(errRemove, IsNil) 136 137 hash, errSecond := w.Commit("Remove foo\n", &CommitOptions{ 138 All: true, 139 Author: defaultSignature(), 140 }) 141 c.Assert(errSecond, IsNil) 142 143 c.Assert(hash, Equals, expected) 144 c.Assert(err, IsNil) 145 146 assertStorageStatus(c, s.Repository, 13, 11, 11, expected) 147} 148 149func (s *WorktreeSuite) TestCommitSign(c *C) { 150 fs := memfs.New() 151 storage := memory.NewStorage() 152 153 r, err := Init(storage, fs) 154 c.Assert(err, IsNil) 155 156 w, err := r.Worktree() 157 c.Assert(err, IsNil) 158 159 util.WriteFile(fs, "foo", []byte("foo"), 0644) 160 161 _, err = w.Add("foo") 162 c.Assert(err, IsNil) 163 164 key := commitSignKey(c, true) 165 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key}) 166 c.Assert(err, IsNil) 167 168 // Verify the commit. 169 pks := new(bytes.Buffer) 170 pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) 171 c.Assert(err, IsNil) 172 173 err = key.Serialize(pkw) 174 c.Assert(err, IsNil) 175 err = pkw.Close() 176 c.Assert(err, IsNil) 177 178 expectedCommit, err := r.CommitObject(hash) 179 c.Assert(err, IsNil) 180 actual, err := expectedCommit.Verify(pks.String()) 181 c.Assert(err, IsNil) 182 c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey) 183} 184 185func (s *WorktreeSuite) TestCommitSignBadKey(c *C) { 186 fs := memfs.New() 187 storage := memory.NewStorage() 188 189 r, err := Init(storage, fs) 190 c.Assert(err, IsNil) 191 192 w, err := r.Worktree() 193 c.Assert(err, IsNil) 194 195 util.WriteFile(fs, "foo", []byte("foo"), 0644) 196 197 _, err = w.Add("foo") 198 c.Assert(err, IsNil) 199 200 key := commitSignKey(c, false) 201 _, err = w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key}) 202 c.Assert(err, Equals, errors.InvalidArgumentError("signing key is encrypted")) 203} 204 205func (s *WorktreeSuite) TestCommitTreeSort(c *C) { 206 path, err := ioutil.TempDir(os.TempDir(), "test-commit-tree-sort") 207 c.Assert(err, IsNil) 208 fs := osfs.New(path) 209 st := filesystem.NewStorage(fs, cache.NewObjectLRUDefault()) 210 r, err := Init(st, nil) 211 c.Assert(err, IsNil) 212 213 r, err = Clone(memory.NewStorage(), memfs.New(), &CloneOptions{ 214 URL: path, 215 }) 216 217 w, err := r.Worktree() 218 c.Assert(err, IsNil) 219 220 mfs := w.Filesystem 221 222 err = mfs.MkdirAll("delta", 0755) 223 c.Assert(err, IsNil) 224 225 for _, p := range []string{"delta_last", "Gamma", "delta/middle", "Beta", "delta-first", "alpha"} { 226 util.WriteFile(mfs, p, []byte("foo"), 0644) 227 _, err = w.Add(p) 228 c.Assert(err, IsNil) 229 } 230 231 _, err = w.Commit("foo\n", &CommitOptions{ 232 All: true, 233 Author: defaultSignature(), 234 }) 235 c.Assert(err, IsNil) 236 237 err = r.Push(&PushOptions{}) 238 c.Assert(err, IsNil) 239 240 cmd := exec.Command("git", "fsck") 241 cmd.Dir = path 242 cmd.Env = os.Environ() 243 buf := &bytes.Buffer{} 244 cmd.Stderr = buf 245 cmd.Stdout = buf 246 247 err = cmd.Run() 248 249 c.Assert(err, IsNil, Commentf("%s", buf.Bytes())) 250} 251 252func assertStorageStatus( 253 c *C, r *Repository, 254 treesCount, blobCount, commitCount int, head plumbing.Hash, 255) { 256 trees, err := r.Storer.IterEncodedObjects(plumbing.TreeObject) 257 c.Assert(err, IsNil) 258 blobs, err := r.Storer.IterEncodedObjects(plumbing.BlobObject) 259 c.Assert(err, IsNil) 260 commits, err := r.Storer.IterEncodedObjects(plumbing.CommitObject) 261 c.Assert(err, IsNil) 262 263 c.Assert(lenIterEncodedObjects(trees), Equals, treesCount) 264 c.Assert(lenIterEncodedObjects(blobs), Equals, blobCount) 265 c.Assert(lenIterEncodedObjects(commits), Equals, commitCount) 266 267 ref, err := r.Head() 268 c.Assert(err, IsNil) 269 c.Assert(ref.Hash(), Equals, head) 270} 271 272func lenIterEncodedObjects(iter storer.EncodedObjectIter) int { 273 count := 0 274 iter.ForEach(func(plumbing.EncodedObject) error { 275 count++ 276 return nil 277 }) 278 279 return count 280} 281 282func defaultSignature() *object.Signature { 283 when, _ := time.Parse(object.DateFormat, "Thu May 04 00:03:43 2017 +0200") 284 return &object.Signature{ 285 Name: "foo", 286 Email: "foo@foo.foo", 287 When: when, 288 } 289} 290 291func commitSignKey(c *C, decrypt bool) *openpgp.Entity { 292 s := strings.NewReader(armoredKeyRing) 293 es, err := openpgp.ReadArmoredKeyRing(s) 294 c.Assert(err, IsNil) 295 296 c.Assert(es, HasLen, 1) 297 c.Assert(es[0].Identities, HasLen, 1) 298 _, ok := es[0].Identities["foo bar <foo@foo.foo>"] 299 c.Assert(ok, Equals, true) 300 301 key := es[0] 302 if decrypt { 303 err = key.PrivateKey.Decrypt([]byte(keyPassphrase)) 304 c.Assert(err, IsNil) 305 } 306 307 return key 308} 309 310const armoredKeyRing = ` 311-----BEGIN PGP PRIVATE KEY BLOCK----- 312 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 365=gIM9 366-----END PGP PRIVATE KEY BLOCK----- 367` 368 369const keyPassphrase = "abcdef0123456789"