fork of go-git with some jj specific features
at v4.7.0 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/object" 13 "gopkg.in/src-d/go-git.v4/plumbing/storer" 14 "gopkg.in/src-d/go-git.v4/storage/filesystem" 15 "gopkg.in/src-d/go-git.v4/storage/memory" 16 17 "golang.org/x/crypto/openpgp" 18 "golang.org/x/crypto/openpgp/armor" 19 "golang.org/x/crypto/openpgp/errors" 20 . "gopkg.in/check.v1" 21 "gopkg.in/src-d/go-billy.v4/memfs" 22 "gopkg.in/src-d/go-billy.v4/osfs" 23 "gopkg.in/src-d/go-billy.v4/util" 24) 25 26func (s *WorktreeSuite) TestCommitInvalidOptions(c *C) { 27 r, err := Init(memory.NewStorage(), memfs.New()) 28 c.Assert(err, IsNil) 29 30 w, err := r.Worktree() 31 c.Assert(err, IsNil) 32 33 hash, err := w.Commit("", &CommitOptions{}) 34 c.Assert(err, Equals, ErrMissingAuthor) 35 c.Assert(hash.IsZero(), Equals, true) 36} 37 38func (s *WorktreeSuite) TestCommitInitial(c *C) { 39 expected := plumbing.NewHash("98c4ac7c29c913f7461eae06e024dc18e80d23a4") 40 41 fs := memfs.New() 42 storage := memory.NewStorage() 43 44 r, err := Init(storage, fs) 45 c.Assert(err, IsNil) 46 47 w, err := r.Worktree() 48 c.Assert(err, IsNil) 49 50 util.WriteFile(fs, "foo", []byte("foo"), 0644) 51 52 _, err = w.Add("foo") 53 c.Assert(err, IsNil) 54 55 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()}) 56 c.Assert(hash, Equals, expected) 57 c.Assert(err, IsNil) 58 59 assertStorageStatus(c, r, 1, 1, 1, expected) 60} 61 62func (s *WorktreeSuite) TestCommitParent(c *C) { 63 expected := plumbing.NewHash("ef3ca05477530b37f48564be33ddd48063fc7a22") 64 65 fs := memfs.New() 66 w := &Worktree{ 67 r: s.Repository, 68 Filesystem: fs, 69 } 70 71 err := w.Checkout(&CheckoutOptions{}) 72 c.Assert(err, IsNil) 73 74 util.WriteFile(fs, "foo", []byte("foo"), 0644) 75 76 _, err = w.Add("foo") 77 c.Assert(err, IsNil) 78 79 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature()}) 80 c.Assert(hash, Equals, expected) 81 c.Assert(err, IsNil) 82 83 assertStorageStatus(c, s.Repository, 13, 11, 10, expected) 84} 85 86func (s *WorktreeSuite) TestCommitAll(c *C) { 87 expected := plumbing.NewHash("aede6f8c9c1c7ec9ca8d287c64b8ed151276fa28") 88 89 fs := memfs.New() 90 w := &Worktree{ 91 r: s.Repository, 92 Filesystem: fs, 93 } 94 95 err := w.Checkout(&CheckoutOptions{}) 96 c.Assert(err, IsNil) 97 98 util.WriteFile(fs, "LICENSE", []byte("foo"), 0644) 99 util.WriteFile(fs, "foo", []byte("foo"), 0644) 100 101 hash, err := w.Commit("foo\n", &CommitOptions{ 102 All: true, 103 Author: defaultSignature(), 104 }) 105 106 c.Assert(hash, Equals, expected) 107 c.Assert(err, IsNil) 108 109 assertStorageStatus(c, s.Repository, 13, 11, 10, expected) 110} 111 112func (s *WorktreeSuite) TestRemoveAndCommitAll(c *C) { 113 expected := plumbing.NewHash("907cd576c6ced2ecd3dab34a72bf9cf65944b9a9") 114 115 fs := memfs.New() 116 w := &Worktree{ 117 r: s.Repository, 118 Filesystem: fs, 119 } 120 121 err := w.Checkout(&CheckoutOptions{}) 122 c.Assert(err, IsNil) 123 124 util.WriteFile(fs, "foo", []byte("foo"), 0644) 125 _, err = w.Add("foo") 126 c.Assert(err, IsNil) 127 128 _, errFirst := w.Commit("Add in Repo\n", &CommitOptions{ 129 Author: defaultSignature(), 130 }) 131 c.Assert(errFirst, IsNil) 132 133 errRemove := fs.Remove("foo") 134 c.Assert(errRemove, IsNil) 135 136 hash, errSecond := w.Commit("Remove foo\n", &CommitOptions{ 137 All: true, 138 Author: defaultSignature(), 139 }) 140 c.Assert(errSecond, IsNil) 141 142 c.Assert(hash, Equals, expected) 143 c.Assert(err, IsNil) 144 145 assertStorageStatus(c, s.Repository, 13, 11, 11, expected) 146} 147 148func (s *WorktreeSuite) TestCommitSign(c *C) { 149 fs := memfs.New() 150 storage := memory.NewStorage() 151 152 r, err := Init(storage, fs) 153 c.Assert(err, IsNil) 154 155 w, err := r.Worktree() 156 c.Assert(err, IsNil) 157 158 util.WriteFile(fs, "foo", []byte("foo"), 0644) 159 160 _, err = w.Add("foo") 161 c.Assert(err, IsNil) 162 163 key := commitSignKey(c, true) 164 hash, err := w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key}) 165 c.Assert(err, IsNil) 166 167 // Verify the commit. 168 pks := new(bytes.Buffer) 169 pkw, err := armor.Encode(pks, openpgp.PublicKeyType, nil) 170 c.Assert(err, IsNil) 171 172 err = key.Serialize(pkw) 173 c.Assert(err, IsNil) 174 err = pkw.Close() 175 c.Assert(err, IsNil) 176 177 expectedCommit, err := r.CommitObject(hash) 178 c.Assert(err, IsNil) 179 actual, err := expectedCommit.Verify(pks.String()) 180 c.Assert(err, IsNil) 181 c.Assert(actual.PrimaryKey, DeepEquals, key.PrimaryKey) 182} 183 184func (s *WorktreeSuite) TestCommitSignBadKey(c *C) { 185 fs := memfs.New() 186 storage := memory.NewStorage() 187 188 r, err := Init(storage, fs) 189 c.Assert(err, IsNil) 190 191 w, err := r.Worktree() 192 c.Assert(err, IsNil) 193 194 util.WriteFile(fs, "foo", []byte("foo"), 0644) 195 196 _, err = w.Add("foo") 197 c.Assert(err, IsNil) 198 199 key := commitSignKey(c, false) 200 _, err = w.Commit("foo\n", &CommitOptions{Author: defaultSignature(), SignKey: key}) 201 c.Assert(err, Equals, errors.InvalidArgumentError("signing key is encrypted")) 202} 203 204func (s *WorktreeSuite) TestCommitTreeSort(c *C) { 205 path, err := ioutil.TempDir(os.TempDir(), "test-commit-tree-sort") 206 c.Assert(err, IsNil) 207 fs := osfs.New(path) 208 st, err := filesystem.NewStorage(fs) 209 c.Assert(err, IsNil) 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=8g3t 366-----END PGP PRIVATE KEY BLOCK----- 367` 368 369const keyPassphrase = "abcdef0123456789"