18
18
package librarian
19
19
20
20
import (
21
+ "encoding/json"
21
22
"fmt"
23
+ "net/http"
24
+ "net/http/httptest"
22
25
"os"
23
26
"os/exec"
24
27
"path/filepath"
@@ -27,6 +30,7 @@ import (
27
30
28
31
"github.com/google/go-cmp/cmp"
29
32
"github.com/google/go-cmp/cmp/cmpopts"
33
+ "github.com/google/go-github/v69/github"
30
34
"github.com/googleapis/librarian/internal/config"
31
35
"gopkg.in/yaml.v3"
32
36
)
@@ -522,6 +526,131 @@ END_COMMIT_OVERRIDE
522
526
}
523
527
}
524
528
529
+ func TestReleaseTagAndRelease (t * testing.T ) {
530
+ t .Parallel ()
531
+ for _ , test := range []struct {
532
+ name string
533
+ prBody string
534
+ push bool
535
+ wantErr bool
536
+ }{
537
+ {
538
+ name : "runs successfully" ,
539
+ prBody : `<details><summary>go-google-cloud-pubsub-v1: v1.0.1</summary>
540
+ ### Features
541
+ - feat: new feature
542
+ </details>` ,
543
+ },
544
+ } {
545
+ t .Run (test .name , func (t * testing.T ) {
546
+ repo := t .TempDir ()
547
+ if err := initRepo (t , repo , "testdata/e2e/release/init/repo_init" ); err != nil {
548
+ t .Fatalf ("prepare test error = %v" , err )
549
+ }
550
+ runGit (t , repo , "tag" , "go-google-cloud-pubsub-v1-1.0.0" )
551
+ newFilePath := filepath .Join (repo , "google-cloud-pubsub/v1" , "new-file.txt" )
552
+ if err := os .WriteFile (newFilePath , []byte ("new file" ), 0644 ); err != nil {
553
+ t .Fatal (err )
554
+ }
555
+ runGit (t , repo , "add" , newFilePath )
556
+ runGit (t , repo , "commit" , "-m" , "feat: new feature" )
557
+ headSHA , err := getHeadSHA (repo )
558
+ if err != nil {
559
+ t .Fatalf ("failed to get head sha: %v" , err )
560
+ }
561
+
562
+ // Set up a mock GitHub API server using httptest.
563
+ // This server will intercept HTTP requests made by the librarian command
564
+ // and provide canned responses, avoiding any real calls to the GitHub API.
565
+ // The handlers below simulate the endpoints that 'release tag-and-release' interacts with.
566
+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
567
+ // Verify that the GitHub token is being sent correctly.
568
+ if r .Header .Get ("Authorization" ) != "Bearer fake-token" {
569
+ t .Errorf ("missing or wrong authorization header: got %q" , r .Header .Get ("Authorization" ))
570
+ }
571
+
572
+ // Mock endpoint for GET /repos/{owner}/{repo}/pulls/{number}
573
+ if r .Method == "GET" && strings .HasSuffix (r .URL .Path , "/pulls/123" ) {
574
+ w .WriteHeader (http .StatusOK )
575
+ // Return a minimal PR object with the body and merge commit SHA.
576
+ fmt .Fprintf (w , `{"number": 123, "body": %q, "merge_commit_sha": %q}` , test .prBody , headSHA )
577
+ return
578
+ }
579
+
580
+ // Mock endpoint for POST /repos/{owner}/{repo}/git/refs (creating the release-please tag)
581
+ if r .Method == "POST" && strings .HasSuffix (r .URL .Path , "/git/refs" ) {
582
+ w .WriteHeader (http .StatusCreated )
583
+ fmt .Fprint (w , `{"ref": "refs/tags/release-please-123"}` )
584
+ return
585
+ }
586
+
587
+ // Mock endpoint for POST /repos/{owner}/{repo}/releases (creating the GitHub Release)
588
+ if r .Method == "POST" && strings .HasSuffix (r .URL .Path , "/releases" ) {
589
+ var newRelease github.RepositoryRelease
590
+ if err := json .NewDecoder (r .Body ).Decode (& newRelease ); err != nil {
591
+ t .Fatalf ("failed to decode request body: %v" , err )
592
+ }
593
+ expectedTagName := "go-google-cloud-pubsub-v1-v1.0.1"
594
+ if * newRelease .TagName != expectedTagName {
595
+ t .Errorf ("unexpected tag name: got %q, want %q" , * newRelease .TagName , expectedTagName )
596
+ }
597
+ if * newRelease .TargetCommitish != headSHA {
598
+ t .Errorf ("unexpected commitish: got %q, want %q" , * newRelease .TargetCommitish , headSHA )
599
+ }
600
+ w .WriteHeader (http .StatusCreated )
601
+ fmt .Fprint (w , `{"name": "v1.0.1"}` )
602
+ return
603
+ }
604
+
605
+ // Mock endpoint for PUT /repos/{owner}/{repo}/issues/{number}/labels (updating labels)
606
+ if r .Method == "PUT" && strings .HasSuffix (r .URL .Path , "/issues/123/labels" ) {
607
+ w .WriteHeader (http .StatusOK )
608
+ fmt .Fprint (w , `[]` )
609
+ return
610
+ }
611
+
612
+ // If any other request is made, fail the test.
613
+ t .Fatalf ("unexpected request: %s %s" , r .Method , r .URL .Path )
614
+ }))
615
+ defer server .Close ()
616
+
617
+ cmdArgs := []string {
618
+ "run" ,
619
+ "github.com/googleapis/librarian/cmd/librarian" ,
620
+ "release" ,
621
+ "tag-and-release" ,
622
+ fmt .Sprintf ("--repo=%s" , repo ),
623
+ fmt .Sprintf ("--github-api-endpoint=%s/" , server .URL ),
624
+ "--pr=https://github.com/googleapis/librarian/pull/123" ,
625
+ }
626
+ if test .push {
627
+ cmdArgs = append (cmdArgs , "--push" )
628
+ }
629
+
630
+ cmd := exec .Command ("go" , cmdArgs ... )
631
+ cmd .Env = append (os .Environ (), "LIBRARIAN_GITHUB_TOKEN=fake-token" )
632
+ cmd .Stderr = os .Stderr
633
+ cmd .Stdout = os .Stdout
634
+ if err := cmd .Run (); err != nil {
635
+ if ! test .wantErr {
636
+ t .Fatalf ("Failed to run release tag-and-release: %v" , err )
637
+ }
638
+ }
639
+ })
640
+ }
641
+ }
642
+
643
+ // getHeadSHA is a helper to get the latest commit SHA from a repo.
644
+ func getHeadSHA (dir string ) (string , error ) {
645
+ cmd := exec .Command ("git" , "rev-parse" , "HEAD" )
646
+ cmd .Dir = dir
647
+ out , err := cmd .Output ()
648
+ if err != nil {
649
+ return "" , err
650
+ }
651
+ return strings .TrimSpace (string (out )), nil
652
+ }
653
+
525
654
// initRepo initiates a git repo in the given directory, copy
526
655
// files from source directory and create a commit.
527
656
func initRepo (t * testing.T , dir , source string ) error {
0 commit comments