github.com/google/go-github/v66@v66.0.0/github/git_commits_test.go (about) 1 // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "encoding/json" 11 "fmt" 12 "io" 13 "net/http" 14 "testing" 15 "time" 16 17 "github.com/google/go-cmp/cmp" 18 ) 19 20 func mockSigner(t *testing.T, signature string, emitErr error, wantMessage string) MessageSignerFunc { 21 return func(w io.Writer, r io.Reader) error { 22 t.Helper() 23 message, err := io.ReadAll(r) 24 assertNilError(t, err) 25 if wantMessage != "" && string(message) != wantMessage { 26 t.Errorf("MessageSignerFunc got %q, want %q", string(message), wantMessage) 27 } 28 assertWrite(t, w, []byte(signature)) 29 return emitErr 30 } 31 } 32 33 func uncalledSigner(t *testing.T) MessageSignerFunc { 34 return func(w io.Writer, r io.Reader) error { 35 t.Error("MessageSignerFunc should not be called") 36 return nil 37 } 38 } 39 40 func TestCommit_Marshal(t *testing.T) { 41 t.Parallel() 42 testJSONMarshal(t, &Commit{}, "{}") 43 44 u := &Commit{ 45 SHA: String("s"), 46 Author: &CommitAuthor{ 47 Date: &Timestamp{referenceTime}, 48 Name: String("n"), 49 Email: String("e"), 50 Login: String("u"), 51 }, 52 Committer: &CommitAuthor{ 53 Date: &Timestamp{referenceTime}, 54 Name: String("n"), 55 Email: String("e"), 56 Login: String("u"), 57 }, 58 Message: String("m"), 59 Tree: &Tree{ 60 SHA: String("s"), 61 Entries: []*TreeEntry{{ 62 SHA: String("s"), 63 Path: String("p"), 64 Mode: String("m"), 65 Type: String("t"), 66 Size: Int(1), 67 Content: String("c"), 68 URL: String("u"), 69 }}, 70 Truncated: Bool(false), 71 }, 72 Parents: nil, 73 Stats: &CommitStats{ 74 Additions: Int(1), 75 Deletions: Int(1), 76 Total: Int(1), 77 }, 78 HTMLURL: String("h"), 79 URL: String("u"), 80 Verification: &SignatureVerification{ 81 Verified: Bool(false), 82 Reason: String("r"), 83 Signature: String("s"), 84 Payload: String("p"), 85 }, 86 NodeID: String("n"), 87 CommentCount: Int(1), 88 } 89 90 want := `{ 91 "sha": "s", 92 "author": { 93 "date": ` + referenceTimeStr + `, 94 "name": "n", 95 "email": "e", 96 "username": "u" 97 }, 98 "committer": { 99 "date": ` + referenceTimeStr + `, 100 "name": "n", 101 "email": "e", 102 "username": "u" 103 }, 104 "message": "m", 105 "tree": { 106 "sha": "s", 107 "tree": [ 108 { 109 "sha": "s", 110 "path": "p", 111 "mode": "m", 112 "type": "t", 113 "size": 1, 114 "content": "c", 115 "url": "u" 116 } 117 ], 118 "truncated": false 119 }, 120 "stats": { 121 "additions": 1, 122 "deletions": 1, 123 "total": 1 124 }, 125 "html_url": "h", 126 "url": "u", 127 "verification": { 128 "verified": false, 129 "reason": "r", 130 "signature": "s", 131 "payload": "p" 132 }, 133 "node_id": "n", 134 "comment_count": 1 135 }` 136 137 testJSONMarshal(t, u, want) 138 } 139 140 func TestGitService_GetCommit(t *testing.T) { 141 t.Parallel() 142 client, mux, _ := setup(t) 143 144 mux.HandleFunc("/repos/o/r/git/commits/s", func(w http.ResponseWriter, r *http.Request) { 145 testMethod(t, r, "GET") 146 fmt.Fprint(w, `{"sha":"s","message":"Commit Message.","author":{"name":"n"}}`) 147 }) 148 149 ctx := context.Background() 150 commit, _, err := client.Git.GetCommit(ctx, "o", "r", "s") 151 if err != nil { 152 t.Errorf("Git.GetCommit returned error: %v", err) 153 } 154 155 want := &Commit{SHA: String("s"), Message: String("Commit Message."), Author: &CommitAuthor{Name: String("n")}} 156 if !cmp.Equal(commit, want) { 157 t.Errorf("Git.GetCommit returned %+v, want %+v", commit, want) 158 } 159 160 const methodName = "GetCommit" 161 testBadOptions(t, methodName, func() (err error) { 162 _, _, err = client.Git.GetCommit(ctx, "\n", "\n", "\n") 163 return err 164 }) 165 166 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 167 got, resp, err := client.Git.GetCommit(ctx, "o", "r", "s") 168 if got != nil { 169 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 170 } 171 return resp, err 172 }) 173 } 174 175 func TestGitService_GetCommit_invalidOwner(t *testing.T) { 176 t.Parallel() 177 client, _, _ := setup(t) 178 179 ctx := context.Background() 180 _, _, err := client.Git.GetCommit(ctx, "%", "%", "%") 181 testURLParseError(t, err) 182 } 183 184 func TestGitService_CreateCommit(t *testing.T) { 185 t.Parallel() 186 client, mux, _ := setup(t) 187 188 input := &Commit{ 189 Message: String("Commit Message."), 190 Tree: &Tree{SHA: String("t")}, 191 Parents: []*Commit{{SHA: String("p")}}, 192 } 193 194 mux.HandleFunc("/repos/o/r/git/commits", func(w http.ResponseWriter, r *http.Request) { 195 v := new(createCommit) 196 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 197 198 testMethod(t, r, "POST") 199 200 want := &createCommit{ 201 Message: input.Message, 202 Tree: String("t"), 203 Parents: []string{"p"}, 204 } 205 if !cmp.Equal(v, want) { 206 t.Errorf("Request body = %+v, want %+v", v, want) 207 } 208 fmt.Fprint(w, `{"sha":"s"}`) 209 }) 210 211 ctx := context.Background() 212 commit, _, err := client.Git.CreateCommit(ctx, "o", "r", input, nil) 213 if err != nil { 214 t.Errorf("Git.CreateCommit returned error: %v", err) 215 } 216 217 want := &Commit{SHA: String("s")} 218 if !cmp.Equal(commit, want) { 219 t.Errorf("Git.CreateCommit returned %+v, want %+v", commit, want) 220 } 221 222 const methodName = "CreateCommit" 223 testBadOptions(t, methodName, func() (err error) { 224 _, _, err = client.Git.CreateCommit(ctx, "\n", "\n", input, nil) 225 return err 226 }) 227 228 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 229 got, resp, err := client.Git.CreateCommit(ctx, "o", "r", input, nil) 230 if got != nil { 231 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 232 } 233 return resp, err 234 }) 235 } 236 237 func TestGitService_CreateSignedCommit(t *testing.T) { 238 t.Parallel() 239 client, mux, _ := setup(t) 240 241 signature := "----- BEGIN PGP SIGNATURE -----\n\naaaa\naaaa\n----- END PGP SIGNATURE -----" 242 243 input := &Commit{ 244 Message: String("Commit Message."), 245 Tree: &Tree{SHA: String("t")}, 246 Parents: []*Commit{{SHA: String("p")}}, 247 Verification: &SignatureVerification{ 248 Signature: String(signature), 249 }, 250 } 251 252 mux.HandleFunc("/repos/o/r/git/commits", func(w http.ResponseWriter, r *http.Request) { 253 v := new(createCommit) 254 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 255 256 testMethod(t, r, "POST") 257 258 want := &createCommit{ 259 Message: input.Message, 260 Tree: String("t"), 261 Parents: []string{"p"}, 262 Signature: String(signature), 263 } 264 if !cmp.Equal(v, want) { 265 t.Errorf("Request body = %+v, want %+v", v, want) 266 } 267 fmt.Fprint(w, `{"sha":"commitSha"}`) 268 }) 269 270 ctx := context.Background() 271 commit, _, err := client.Git.CreateCommit(ctx, "o", "r", input, nil) 272 if err != nil { 273 t.Errorf("Git.CreateCommit returned error: %v", err) 274 } 275 276 want := &Commit{SHA: String("commitSha")} 277 if !cmp.Equal(commit, want) { 278 t.Errorf("Git.CreateCommit returned %+v, want %+v", commit, want) 279 } 280 281 const methodName = "CreateCommit" 282 testBadOptions(t, methodName, func() (err error) { 283 _, _, err = client.Git.CreateCommit(ctx, "\n", "\n", input, nil) 284 return err 285 }) 286 287 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 288 got, resp, err := client.Git.CreateCommit(ctx, "o", "r", input, nil) 289 if got != nil { 290 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 291 } 292 return resp, err 293 }) 294 } 295 296 func TestGitService_CreateSignedCommitWithInvalidParams(t *testing.T) { 297 t.Parallel() 298 client, _, _ := setup(t) 299 300 input := &Commit{} 301 302 ctx := context.Background() 303 opts := CreateCommitOptions{Signer: uncalledSigner(t)} 304 _, _, err := client.Git.CreateCommit(ctx, "o", "r", input, &opts) 305 if err == nil { 306 t.Errorf("Expected error to be returned because invalid params were passed") 307 } 308 } 309 310 func TestGitService_CreateCommitWithNilCommit(t *testing.T) { 311 t.Parallel() 312 client, _, _ := setup(t) 313 314 ctx := context.Background() 315 _, _, err := client.Git.CreateCommit(ctx, "o", "r", nil, nil) 316 if err == nil { 317 t.Errorf("Expected error to be returned because commit=nil") 318 } 319 } 320 321 func TestGitService_CreateCommit_WithSigner(t *testing.T) { 322 t.Parallel() 323 client, mux, _ := setup(t) 324 325 signature := "my voice is my password" 326 date := time.Date(2017, time.May, 4, 0, 3, 43, 0, time.FixedZone("CEST", 2*3600)) 327 author := CommitAuthor{ 328 Name: String("go-github"), 329 Email: String("go-github@github.com"), 330 Date: &Timestamp{date}, 331 } 332 wantMessage := `tree t 333 parent p 334 author go-github <go-github@github.com> 1493849023 +0200 335 committer go-github <go-github@github.com> 1493849023 +0200 336 337 Commit Message.` 338 sha := "commitSha" 339 input := &Commit{ 340 SHA: &sha, 341 Message: String("Commit Message."), 342 Tree: &Tree{SHA: String("t")}, 343 Parents: []*Commit{{SHA: String("p")}}, 344 Author: &author, 345 } 346 wantBody := createCommit{ 347 Message: input.Message, 348 Tree: String("t"), 349 Parents: []string{"p"}, 350 Author: &author, 351 Signature: &signature, 352 } 353 var gotBody createCommit 354 mux.HandleFunc("/repos/o/r/git/commits", func(w http.ResponseWriter, r *http.Request) { 355 assertNilError(t, json.NewDecoder(r.Body).Decode(&gotBody)) 356 testMethod(t, r, "POST") 357 fmt.Fprintf(w, `{"sha":"%s"}`, sha) 358 }) 359 ctx := context.Background() 360 wantCommit := &Commit{SHA: String(sha)} 361 opts := CreateCommitOptions{Signer: mockSigner(t, signature, nil, wantMessage)} 362 commit, _, err := client.Git.CreateCommit(ctx, "o", "r", input, &opts) 363 assertNilError(t, err) 364 if cmp.Diff(gotBody, wantBody) != "" { 365 t.Errorf("Request body = %+v, want %+v\n%s", gotBody, wantBody, cmp.Diff(gotBody, wantBody)) 366 } 367 if cmp.Diff(commit, wantCommit) != "" { 368 t.Errorf("Git.CreateCommit returned %+v, want %+v\n%s", commit, wantCommit, cmp.Diff(commit, wantCommit)) 369 } 370 } 371 372 func TestGitService_createSignature_nilSigner(t *testing.T) { 373 t.Parallel() 374 a := &createCommit{ 375 Message: String("Commit Message."), 376 Tree: String("t"), 377 Parents: []string{"p"}, 378 } 379 380 _, err := createSignature(nil, a) 381 382 if err == nil { 383 t.Errorf("Expected error to be returned because no author was passed") 384 } 385 } 386 387 func TestGitService_createSignature_nilCommit(t *testing.T) { 388 t.Parallel() 389 _, err := createSignature(uncalledSigner(t), nil) 390 391 if err == nil { 392 t.Errorf("Expected error to be returned because no author was passed") 393 } 394 } 395 396 func TestGitService_createSignature_signerError(t *testing.T) { 397 t.Parallel() 398 a := &createCommit{ 399 Message: String("Commit Message."), 400 Tree: String("t"), 401 Parents: []string{"p"}, 402 Author: &CommitAuthor{Name: String("go-github")}, 403 } 404 405 signer := mockSigner(t, "", fmt.Errorf("signer error"), "") 406 _, err := createSignature(signer, a) 407 408 if err == nil { 409 t.Errorf("Expected error to be returned because signer returned an error") 410 } 411 } 412 413 func TestGitService_createSignatureMessage_nilCommit(t *testing.T) { 414 t.Parallel() 415 _, err := createSignatureMessage(nil) 416 if err == nil { 417 t.Errorf("Expected error to be returned due to nil key") 418 } 419 } 420 421 func TestGitService_createSignatureMessage_nilMessage(t *testing.T) { 422 t.Parallel() 423 date, _ := time.Parse("Mon Jan 02 15:04:05 2006 -0700", "Thu May 04 00:03:43 2017 +0200") 424 425 _, err := createSignatureMessage(&createCommit{ 426 Message: nil, 427 Parents: []string{"p"}, 428 Author: &CommitAuthor{ 429 Name: String("go-github"), 430 Email: String("go-github@github.com"), 431 Date: &Timestamp{date}, 432 }, 433 }) 434 if err == nil { 435 t.Errorf("Expected error to be returned due to nil key") 436 } 437 } 438 439 func TestGitService_createSignatureMessage_emptyMessage(t *testing.T) { 440 t.Parallel() 441 date, _ := time.Parse("Mon Jan 02 15:04:05 2006 -0700", "Thu May 04 00:03:43 2017 +0200") 442 emptyString := "" 443 _, err := createSignatureMessage(&createCommit{ 444 Message: &emptyString, 445 Parents: []string{"p"}, 446 Author: &CommitAuthor{ 447 Name: String("go-github"), 448 Email: String("go-github@github.com"), 449 Date: &Timestamp{date}, 450 }, 451 }) 452 if err == nil { 453 t.Errorf("Expected error to be returned due to nil key") 454 } 455 } 456 457 func TestGitService_createSignatureMessage_nilAuthor(t *testing.T) { 458 t.Parallel() 459 _, err := createSignatureMessage(&createCommit{ 460 Message: String("Commit Message."), 461 Parents: []string{"p"}, 462 Author: nil, 463 }) 464 if err == nil { 465 t.Errorf("Expected error to be returned due to nil key") 466 } 467 } 468 469 func TestGitService_createSignatureMessage_withoutTree(t *testing.T) { 470 t.Parallel() 471 date, _ := time.Parse("Mon Jan 02 15:04:05 2006 -0700", "Thu May 04 00:03:43 2017 +0200") 472 473 msg, _ := createSignatureMessage(&createCommit{ 474 Message: String("Commit Message."), 475 Parents: []string{"p"}, 476 Author: &CommitAuthor{ 477 Name: String("go-github"), 478 Email: String("go-github@github.com"), 479 Date: &Timestamp{date}, 480 }, 481 }) 482 expected := `parent p 483 author go-github <go-github@github.com> 1493849023 +0200 484 committer go-github <go-github@github.com> 1493849023 +0200 485 486 Commit Message.` 487 if msg != expected { 488 t.Errorf("Returned message incorrect. returned %s, want %s", msg, expected) 489 } 490 } 491 492 func TestGitService_createSignatureMessage_withoutCommitter(t *testing.T) { 493 t.Parallel() 494 date, _ := time.Parse("Mon Jan 02 15:04:05 2006 -0700", "Thu May 04 00:03:43 2017 +0200") 495 496 msg, _ := createSignatureMessage(&createCommit{ 497 Message: String("Commit Message."), 498 Parents: []string{"p"}, 499 Author: &CommitAuthor{ 500 Name: String("go-github"), 501 Email: String("go-github@github.com"), 502 Date: &Timestamp{date}, 503 }, 504 Committer: &CommitAuthor{ 505 Name: String("foo"), 506 Email: String("foo@bar.com"), 507 Date: &Timestamp{date}, 508 }, 509 }) 510 expected := `parent p 511 author go-github <go-github@github.com> 1493849023 +0200 512 committer foo <foo@bar.com> 1493849023 +0200 513 514 Commit Message.` 515 if msg != expected { 516 t.Errorf("Returned message incorrect. returned %s, want %s", msg, expected) 517 } 518 } 519 520 func TestGitService_CreateCommit_invalidOwner(t *testing.T) { 521 t.Parallel() 522 client, _, _ := setup(t) 523 524 ctx := context.Background() 525 _, _, err := client.Git.CreateCommit(ctx, "%", "%", &Commit{}, nil) 526 testURLParseError(t, err) 527 } 528 529 func TestSignatureVerification_Marshal(t *testing.T) { 530 t.Parallel() 531 testJSONMarshal(t, &SignatureVerification{}, "{}") 532 533 u := &SignatureVerification{ 534 Verified: Bool(true), 535 Reason: String("reason"), 536 Signature: String("sign"), 537 Payload: String("payload"), 538 } 539 540 want := `{ 541 "verified": true, 542 "reason": "reason", 543 "signature": "sign", 544 "payload": "payload" 545 }` 546 547 testJSONMarshal(t, u, want) 548 } 549 550 func TestCommitAuthor_Marshal(t *testing.T) { 551 t.Parallel() 552 testJSONMarshal(t, &CommitAuthor{}, "{}") 553 554 u := &CommitAuthor{ 555 Date: &Timestamp{referenceTime}, 556 Name: String("name"), 557 Email: String("email"), 558 Login: String("login"), 559 } 560 561 want := `{ 562 "date": ` + referenceTimeStr + `, 563 "name": "name", 564 "email": "email", 565 "username": "login" 566 }` 567 568 testJSONMarshal(t, u, want) 569 } 570 571 func TestCreateCommit_Marshal(t *testing.T) { 572 t.Parallel() 573 testJSONMarshal(t, &createCommit{}, "{}") 574 575 u := &createCommit{ 576 Author: &CommitAuthor{ 577 Date: &Timestamp{referenceTime}, 578 Name: String("name"), 579 Email: String("email"), 580 Login: String("login"), 581 }, 582 Committer: &CommitAuthor{ 583 Date: &Timestamp{referenceTime}, 584 Name: String("name"), 585 Email: String("email"), 586 Login: String("login"), 587 }, 588 Message: String("message"), 589 Tree: String("tree"), 590 Parents: []string{"p"}, 591 Signature: String("sign"), 592 } 593 594 want := `{ 595 "author": { 596 "date": ` + referenceTimeStr + `, 597 "name": "name", 598 "email": "email", 599 "username": "login" 600 }, 601 "committer": { 602 "date": ` + referenceTimeStr + `, 603 "name": "name", 604 "email": "email", 605 "username": "login" 606 }, 607 "message": "message", 608 "tree": "tree", 609 "parents": [ 610 "p" 611 ], 612 "signature": "sign" 613 }` 614 615 testJSONMarshal(t, u, want) 616 }