Skip to content

Commit b38097e

Browse files
authored
fix(testing): align tag-and-release e2e test with API workflow (#2240)
Updates the end-to-end test for the 'release tag-and-release' command to align with the refactoring introduced in commit 2807adf. The refactoring removed the command's dependency on a local repository clone, causing the existing e2e test to fail as it was still based on a local git setup. The command now fetches the state.yaml file directly from the GitHub API. This change updates the test by: - Removing the unnecessary local git repository setup. - Modifying the mock HTTP server to correctly simulate the multi-step API process used by the go-github client to download a file (directory listing followed by content download). - Updating the 'newTagAndReleaseRunner' to correctly use the 'github-api-endpoint' flag, ensuring the client is properly directed to the mock server during tests. Part of #1013. Note: improving coverage for new code in tag_and_release.go requires tests with much setup. Given that the new code is a simple error check, and given the e2e test uses the code, codecov report is ignored.
1 parent 8305885 commit b38097e

File tree

2 files changed

+62
-30
lines changed

2 files changed

+62
-30
lines changed

e2e_test.go

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -543,37 +543,69 @@ func TestReleaseTagAndRelease(t *testing.T) {
543543
},
544544
} {
545545
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-
}
546+
headSHA := "abcdef123456"
561547

562548
// Set up a mock GitHub API server using httptest.
563549
// This server will intercept HTTP requests made by the librarian command
564550
// and provide canned responses, avoiding any real calls to the GitHub API.
565551
// 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) {
552+
var server *httptest.Server
553+
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
567554
// Verify that the GitHub token is being sent correctly.
568555
if r.Header.Get("Authorization") != "Bearer fake-token" {
569556
t.Errorf("missing or wrong authorization header: got %q", r.Header.Get("Authorization"))
570557
}
571558

559+
const stateYAMLContent = `
560+
image: gcr.io/some-project/some-image:latest
561+
libraries:
562+
- id: go-google-cloud-pubsub-v1
563+
source_roots:
564+
- google-cloud-pubsub/v1
565+
tag_format: go-google-cloud-pubsub-v1-{version}
566+
`
567+
// The download URL can be any unique path. The mock server will handle it.
568+
downloadURL := server.URL + "/raw/librarian/state.yaml"
569+
570+
// Handler for the .librarian DIRECTORY listing request.
571+
// The client sends this to find the state.yaml file.
572+
if r.Method == "GET" && r.URL.Path == "/repos/googleapis/librarian/contents/.librarian" {
573+
w.Header().Set("Content-Type", "application/json")
574+
w.WriteHeader(http.StatusOK)
575+
// CRITICAL: The response for the directory listing must include the `download_url` for the file.
576+
fmt.Fprintf(w, `[{"name": "state.yaml", "path": ".librarian/state.yaml", "type": "file", "download_url": %q}]`, downloadURL)
577+
return
578+
}
579+
580+
// Handler for the raw CONTENT download request.
581+
// The client hits this endpoint after extracting the download_url from the directory listing.
582+
if r.Method == "GET" && r.URL.Path == "/raw/librarian/state.yaml" {
583+
w.WriteHeader(http.StatusOK)
584+
fmt.Fprint(w, stateYAMLContent)
585+
return
586+
}
587+
588+
// Mock endpoint for the .librarian directory listing.
589+
// This handles the preliminary request the GitHub client makes before fetching a file.
590+
if r.Method == "GET" && r.URL.Path == "/repos/googleapis/librarian/contents/.librarian" {
591+
w.WriteHeader(http.StatusOK)
592+
// This response tells the client that the directory contains a file named state.yaml
593+
fmt.Fprint(w, `[{"name": "state.yaml", "path": ".librarian/state.yaml", "type": "file"}]`)
594+
return
595+
}
596+
597+
// Mock endpoint for GET /.librarian/state.yaml
598+
if r.Method == "GET" && strings.HasSuffix(r.URL.Path, ".librarian/state.yaml") {
599+
w.WriteHeader(http.StatusOK)
600+
fmt.Fprint(w, stateYAMLContent)
601+
return
602+
}
603+
572604
// Mock endpoint for GET /repos/{owner}/{repo}/pulls/{number}
573605
if r.Method == "GET" && strings.HasSuffix(r.URL.Path, "/pulls/123") {
574606
w.WriteHeader(http.StatusOK)
575607
// 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)
608+
fmt.Fprintf(w, `{"number": 123, "body": %q, "merge_commit_sha": %q, "base": {"ref": "main"}}`, test.prBody, headSHA)
577609
return
578610
}
579611

@@ -619,7 +651,7 @@ func TestReleaseTagAndRelease(t *testing.T) {
619651
"github.com/googleapis/librarian/cmd/librarian",
620652
"release",
621653
"tag-and-release",
622-
fmt.Sprintf("--repo=%s", repo),
654+
"--repo=https://github.com/googleapis/librarian",
623655
fmt.Sprintf("--github-api-endpoint=%s/", server.URL),
624656
"--pr=https://github.com/googleapis/librarian/pull/123",
625657
}
@@ -640,17 +672,6 @@ func TestReleaseTagAndRelease(t *testing.T) {
640672
}
641673
}
642674

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-
654675
// initRepo initiates a git repo in the given directory, copy
655676
// files from source directory and create a commit.
656677
func initRepo(t *testing.T, dir, source string) error {

internal/librarian/tag_and_release.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"errors"
2020
"fmt"
2121
"log/slog"
22+
"net/url"
2223
"regexp"
2324
"slices"
2425
"strconv"
@@ -55,6 +56,15 @@ func newTagAndReleaseRunner(cfg *config.Config) (*tagAndReleaseRunner, error) {
5556
return nil, err
5657
}
5758
ghClient := github.NewClient(cfg.GitHubToken, repo)
59+
// If a custom GitHub API endpoint is provided (for testing),
60+
// parse it and set it as the BaseURL on the GitHub client.
61+
if cfg.GitHubAPIEndpoint != "" {
62+
endpoint, err := url.Parse(cfg.GitHubAPIEndpoint)
63+
if err != nil {
64+
return nil, fmt.Errorf("failed to parse github-api-endpoint: %w", err)
65+
}
66+
ghClient.BaseURL = endpoint
67+
}
5868
return &tagAndReleaseRunner{
5969
ghClient: ghClient,
6070
pullRequest: cfg.PullRequest,
@@ -200,8 +210,9 @@ func parsePullRequestBody(body string) []libraryRelease {
200210
Library: library,
201211
Body: content,
202212
})
213+
} else {
214+
slog.Warn("failed to parse pull request body", "match", strings.Join(match, "\n"))
203215
}
204-
slog.Warn("failed to parse pull request body", "match", strings.Join(match, "\n"))
205216
}
206217

207218
return parsedBodies

0 commit comments

Comments
 (0)