
- Add comprehensive Git workflow automation tools - Include branch management utilities - Add commit helpers with conventional commit support - Implement GitHub integration for PR management - Add configuration management system - Include comprehensive test coverage - Add professional documentation and examples
970 lines
27 KiB
Go
970 lines
27 KiB
Go
package github
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func setupTestServer(t *testing.T, handler http.HandlerFunc) (*httptest.Server, *Client) {
|
|
t.Helper()
|
|
|
|
// Create a test server
|
|
server := httptest.NewServer(handler)
|
|
|
|
// Create a client with the test server URL
|
|
client := &Client{
|
|
baseURL: server.URL,
|
|
httpClient: server.Client(),
|
|
token: "test-token",
|
|
}
|
|
|
|
return server, client
|
|
}
|
|
|
|
func TestNewClient(t *testing.T) {
|
|
// We can't easily test the config path without modifying global state,
|
|
// so we'll just test that it doesn't fail with a valid config
|
|
// This would require setting up the config package first
|
|
}
|
|
|
|
func TestIsGitHubURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
url string
|
|
want bool
|
|
}{
|
|
{
|
|
name: "GitHub HTTPS URL",
|
|
url: "https://github.com/user/repo.git",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "GitHub SSH URL",
|
|
url: "git@github.com:user/repo.git",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "Non-GitHub HTTPS URL",
|
|
url: "https://example.com/user/repo.git",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "Non-GitHub SSH URL",
|
|
url: "git@example.com:user/repo.git",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "Invalid URL",
|
|
url: "not-a-url",
|
|
want: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := IsGitHubURL(tt.url); got != tt.want {
|
|
t.Errorf("IsGitHubURL(%q) = %v, want %v", tt.url, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseGitHubURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
url string
|
|
owner string
|
|
repo string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "GitHub HTTPS URL",
|
|
url: "https://github.com/user/repo.git",
|
|
owner: "user",
|
|
repo: "repo",
|
|
},
|
|
{
|
|
name: "GitHub HTTPS URL without .git",
|
|
url: "https://github.com/user/repo",
|
|
owner: "user",
|
|
repo: "repo",
|
|
},
|
|
{
|
|
name: "GitHub SSH URL",
|
|
url: "git@github.com:user/repo.git",
|
|
owner: "user",
|
|
repo: "repo",
|
|
},
|
|
{
|
|
name: "Invalid URL",
|
|
url: "not-a-url",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
owner, repo, err := ParseGitHubURL(tt.url)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("ParseGitHubURL(%q) error = %v, wantErr %v", tt.url, err, tt.wantErr)
|
|
return
|
|
}
|
|
if !tt.wantErr {
|
|
if owner != tt.owner {
|
|
t.Errorf("ParseGitHubURL(%q) owner = %v, want %v", tt.url, owner, tt.owner)
|
|
}
|
|
if repo != tt.repo {
|
|
t.Errorf("ParseGitHubURL(%q) repo = %v, want %v", tt.url, repo, tt.repo)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCreatePullRequest(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodPost {
|
|
t.Errorf("Expected POST request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/repos/owner/repo/pulls" {
|
|
t.Errorf("Expected path to be '/repos/owner/repo/pulls', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
w.Write([]byte(`{
|
|
"id": 1,
|
|
"number": 123,
|
|
"state": "open",
|
|
"title": "Test PR",
|
|
"body": "Test PR body",
|
|
"html_url": "https://github.com/owner/repo/pull/123",
|
|
"user": {
|
|
"login": "testuser",
|
|
"id": 1
|
|
},
|
|
"head": {
|
|
"label": "owner:feature",
|
|
"ref": "feature",
|
|
"sha": "abc123"
|
|
},
|
|
"base": {
|
|
"label": "owner:main",
|
|
"ref": "main",
|
|
"sha": "def456"
|
|
}
|
|
}`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Set repository on client
|
|
client.SetRepository("owner", "repo")
|
|
|
|
// Create a pull request
|
|
pr := &PullRequestRequest{
|
|
Title: "Test PR",
|
|
Body: "Test PR body",
|
|
Head: "feature",
|
|
Base: "main",
|
|
}
|
|
|
|
pullRequest, err := client.CreatePullRequest(context.Background(), pr)
|
|
if err != nil {
|
|
t.Fatalf("CreatePullRequest failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if pullRequest.ID != 1 {
|
|
t.Errorf("Expected ID to be 1, got %d", pullRequest.ID)
|
|
}
|
|
|
|
if pullRequest.Number != 123 {
|
|
t.Errorf("Expected Number to be 123, got %d", pullRequest.Number)
|
|
}
|
|
|
|
if pullRequest.Title != "Test PR" {
|
|
t.Errorf("Expected Title to be 'Test PR', got '%s'", pullRequest.Title)
|
|
}
|
|
|
|
if pullRequest.Body != "Test PR body" {
|
|
t.Errorf("Expected Body to be 'Test PR body', got '%s'", pullRequest.Body)
|
|
}
|
|
|
|
if pullRequest.HTMLURL != "https://github.com/owner/repo/pull/123" {
|
|
t.Errorf("Expected HTMLURL to be 'https://github.com/owner/repo/pull/123', got '%s'", pullRequest.HTMLURL)
|
|
}
|
|
}
|
|
|
|
func TestGetPullRequests(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodGet {
|
|
t.Errorf("Expected GET request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/repos/owner/repo/pulls" {
|
|
t.Errorf("Expected path to be '/repos/owner/repo/pulls', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check request query
|
|
if r.URL.Query().Get("state") != "open" {
|
|
t.Errorf("Expected state query to be 'open', got '%s'", r.URL.Query().Get("state"))
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`[
|
|
{
|
|
"id": 1,
|
|
"number": 123,
|
|
"state": "open",
|
|
"title": "Test PR 1",
|
|
"body": "Test PR body 1",
|
|
"html_url": "https://github.com/owner/repo/pull/123",
|
|
"user": {
|
|
"login": "testuser",
|
|
"id": 1
|
|
},
|
|
"head": {
|
|
"label": "owner:feature1",
|
|
"ref": "feature1",
|
|
"sha": "abc123"
|
|
},
|
|
"base": {
|
|
"label": "owner:main",
|
|
"ref": "main",
|
|
"sha": "def456"
|
|
}
|
|
},
|
|
{
|
|
"id": 2,
|
|
"number": 124,
|
|
"state": "open",
|
|
"title": "Test PR 2",
|
|
"body": "Test PR body 2",
|
|
"html_url": "https://github.com/owner/repo/pull/124",
|
|
"user": {
|
|
"login": "testuser",
|
|
"id": 1
|
|
},
|
|
"head": {
|
|
"label": "owner:feature2",
|
|
"ref": "feature2",
|
|
"sha": "ghi789"
|
|
},
|
|
"base": {
|
|
"label": "owner:main",
|
|
"ref": "main",
|
|
"sha": "def456"
|
|
}
|
|
}
|
|
]`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Set repository on client
|
|
client.SetRepository("owner", "repo")
|
|
|
|
// Get pull requests
|
|
pullRequests, err := client.GetPullRequests(context.Background(), "open")
|
|
if err != nil {
|
|
t.Fatalf("GetPullRequests failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if len(pullRequests) != 2 {
|
|
t.Errorf("Expected 2 pull requests, got %d", len(pullRequests))
|
|
}
|
|
|
|
if pullRequests[0].ID != 1 {
|
|
t.Errorf("Expected first PR ID to be 1, got %d", pullRequests[0].ID)
|
|
}
|
|
|
|
if pullRequests[0].Number != 123 {
|
|
t.Errorf("Expected first PR Number to be 123, got %d", pullRequests[0].Number)
|
|
}
|
|
|
|
if pullRequests[0].Title != "Test PR 1" {
|
|
t.Errorf("Expected first PR Title to be 'Test PR 1', got '%s'", pullRequests[0].Title)
|
|
}
|
|
|
|
if pullRequests[1].ID != 2 {
|
|
t.Errorf("Expected second PR ID to be 2, got %d", pullRequests[1].ID)
|
|
}
|
|
|
|
if pullRequests[1].Number != 124 {
|
|
t.Errorf("Expected second PR Number to be 124, got %d", pullRequests[1].Number)
|
|
}
|
|
|
|
if pullRequests[1].Title != "Test PR 2" {
|
|
t.Errorf("Expected second PR Title to be 'Test PR 2', got '%s'", pullRequests[1].Title)
|
|
}
|
|
}
|
|
|
|
func TestMergePullRequest(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodPut {
|
|
t.Errorf("Expected PUT request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/repos/owner/repo/pulls/123/merge" {
|
|
t.Errorf("Expected path to be '/repos/owner/repo/pulls/123/merge', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`{
|
|
"sha": "merged123",
|
|
"merged": true,
|
|
"message": "Pull Request successfully merged"
|
|
}`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Set repository on client
|
|
client.SetRepository("owner", "repo")
|
|
|
|
// Merge a pull request
|
|
mergeRequest := &MergePullRequestRequest{
|
|
MergeMethod: "merge",
|
|
}
|
|
|
|
mergeResponse, err := client.MergePullRequest(context.Background(), 123, mergeRequest)
|
|
if err != nil {
|
|
t.Fatalf("MergePullRequest failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if mergeResponse.SHA != "merged123" {
|
|
t.Errorf("Expected SHA to be 'merged123', got '%s'", mergeResponse.SHA)
|
|
}
|
|
|
|
if !mergeResponse.Merged {
|
|
t.Errorf("Expected Merged to be true, got false")
|
|
}
|
|
|
|
if mergeResponse.Message != "Pull Request successfully merged" {
|
|
t.Errorf("Expected Message to be 'Pull Request successfully merged', got '%s'", mergeResponse.Message)
|
|
}
|
|
}
|
|
|
|
func TestGetUser(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodGet {
|
|
t.Errorf("Expected GET request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/user" {
|
|
t.Errorf("Expected path to be '/user', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`{
|
|
"login": "testuser",
|
|
"id": 1,
|
|
"node_id": "MDQ6VXNlcjE=",
|
|
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
|
"gravatar_id": "",
|
|
"url": "https://api.github.com/users/testuser",
|
|
"html_url": "https://github.com/testuser",
|
|
"followers_url": "https://api.github.com/users/testuser/followers",
|
|
"following_url": "https://api.github.com/users/testuser/following{/other_user}",
|
|
"gists_url": "https://api.github.com/users/testuser/gists{/gist_id}",
|
|
"starred_url": "https://api.github.com/users/testuser/starred{/owner}{/repo}",
|
|
"subscriptions_url": "https://api.github.com/users/testuser/subscriptions",
|
|
"organizations_url": "https://api.github.com/users/testuser/orgs",
|
|
"repos_url": "https://api.github.com/users/testuser/repos",
|
|
"events_url": "https://api.github.com/users/testuser/events{/privacy}",
|
|
"received_events_url": "https://api.github.com/users/testuser/received_events",
|
|
"type": "User",
|
|
"site_admin": false,
|
|
"name": "Test User",
|
|
"company": null,
|
|
"blog": "",
|
|
"location": "San Francisco",
|
|
"email": "testuser@example.com",
|
|
"hireable": null,
|
|
"bio": null,
|
|
"twitter_username": null,
|
|
"public_repos": 2,
|
|
"public_gists": 1,
|
|
"followers": 1,
|
|
"following": 0,
|
|
"created_at": "2023-01-01T00:00:00Z",
|
|
"updated_at": "2023-01-01T00:00:00Z"
|
|
}`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Get user
|
|
user, err := client.GetUser(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("GetUser failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if user.Login != "testuser" {
|
|
t.Errorf("Expected Login to be 'testuser', got '%s'", user.Login)
|
|
}
|
|
|
|
if user.ID != 1 {
|
|
t.Errorf("Expected ID to be 1, got %d", user.ID)
|
|
}
|
|
|
|
if user.Name != "Test User" {
|
|
t.Errorf("Expected Name to be 'Test User', got '%s'", user.Name)
|
|
}
|
|
|
|
if user.Email != "testuser@example.com" {
|
|
t.Errorf("Expected Email to be 'testuser@example.com', got '%s'", user.Email)
|
|
}
|
|
}
|
|
|
|
func TestGetRepository(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodGet {
|
|
t.Errorf("Expected GET request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/repos/owner/repo" {
|
|
t.Errorf("Expected path to be '/repos/owner/repo', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`{
|
|
"id": 1,
|
|
"node_id": "MDEwOlJlcG9zaXRvcnkx",
|
|
"name": "repo",
|
|
"full_name": "owner/repo",
|
|
"private": false,
|
|
"owner": {
|
|
"login": "owner",
|
|
"id": 1,
|
|
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
|
"gravatar_id": "",
|
|
"url": "https://api.github.com/users/owner",
|
|
"html_url": "https://github.com/owner",
|
|
"followers_url": "https://api.github.com/users/owner/followers",
|
|
"following_url": "https://api.github.com/users/owner/following{/other_user}",
|
|
"gists_url": "https://api.github.com/users/owner/gists{/gist_id}",
|
|
"starred_url": "https://api.github.com/users/owner/starred{/owner}{/repo}",
|
|
"subscriptions_url": "https://api.github.com/users/owner/subscriptions",
|
|
"organizations_url": "https://api.github.com/users/owner/orgs",
|
|
"repos_url": "https://api.github.com/users/owner/repos",
|
|
"events_url": "https://api.github.com/users/owner/events{/privacy}",
|
|
"received_events_url": "https://api.github.com/users/owner/received_events",
|
|
"type": "User",
|
|
"site_admin": false
|
|
},
|
|
"html_url": "https://github.com/owner/repo",
|
|
"description": "Test repository",
|
|
"fork": false,
|
|
"url": "https://api.github.com/repos/owner/repo",
|
|
"forks_url": "https://api.github.com/repos/owner/repo/forks",
|
|
"keys_url": "https://api.github.com/repos/owner/repo/keys{/key_id}",
|
|
"collaborators_url": "https://api.github.com/repos/owner/repo/collaborators{/collaborator}",
|
|
"teams_url": "https://api.github.com/repos/owner/repo/teams",
|
|
"hooks_url": "https://api.github.com/repos/owner/repo/hooks",
|
|
"issue_events_url": "https://api.github.com/repos/owner/repo/issues/events{/number}",
|
|
"events_url": "https://api.github.com/repos/owner/repo/events",
|
|
"assignees_url": "https://api.github.com/repos/owner/repo/assignees{/user}",
|
|
"branches_url": "https://api.github.com/repos/owner/repo/branches{/branch}",
|
|
"tags_url": "https://api.github.com/repos/owner/repo/tags",
|
|
"blobs_url": "https://api.github.com/repos/owner/repo/git/blobs{/sha}",
|
|
"git_tags_url": "https://api.github.com/repos/owner/repo/git/tags{/sha}",
|
|
"git_refs_url": "https://api.github.com/repos/owner/repo/git/refs{/sha}",
|
|
"trees_url": "https://api.github.com/repos/owner/repo/git/trees{/sha}",
|
|
"statuses_url": "https://api.github.com/repos/owner/repo/statuses/{sha}",
|
|
"languages_url": "https://api.github.com/repos/owner/repo/languages",
|
|
"stargazers_url": "https://api.github.com/repos/owner/repo/stargazers",
|
|
"contributors_url": "https://api.github.com/repos/owner/repo/contributors",
|
|
"subscribers_url": "https://api.github.com/repos/owner/repo/subscribers",
|
|
"subscription_url": "https://api.github.com/repos/owner/repo/subscription",
|
|
"commits_url": "https://api.github.com/repos/owner/repo/commits{/sha}",
|
|
"git_commits_url": "https://api.github.com/repos/owner/repo/git/commits{/sha}",
|
|
"comments_url": "https://api.github.com/repos/owner/repo/comments{/number}",
|
|
"issue_comment_url": "https://api.github.com/repos/owner/repo/issues/comments{/number}",
|
|
"contents_url": "https://api.github.com/repos/owner/repo/contents/{+path}",
|
|
"compare_url": "https://api.github.com/repos/owner/repo/compare/{base}...{head}",
|
|
"merges_url": "https://api.github.com/repos/owner/repo/merges",
|
|
"archive_url": "https://api.github.com/repos/owner/repo/{archive_format}{/ref}",
|
|
"downloads_url": "https://api.github.com/repos/owner/repo/downloads",
|
|
"issues_url": "https://api.github.com/repos/owner/repo/issues{/number}",
|
|
"pulls_url": "https://api.github.com/repos/owner/repo/pulls{/number}",
|
|
"milestones_url": "https://api.github.com/repos/owner/repo/milestones{/number}",
|
|
"notifications_url": "https://api.github.com/repos/owner/repo/notifications{?since,all,participating}",
|
|
"labels_url": "https://api.github.com/repos/owner/repo/labels{/name}",
|
|
"releases_url": "https://api.github.com/repos/owner/repo/releases{/id}",
|
|
"deployments_url": "https://api.github.com/repos/owner/repo/deployments",
|
|
"created_at": "2023-01-01T00:00:00Z",
|
|
"updated_at": "2023-01-01T00:00:00Z",
|
|
"pushed_at": "2023-01-01T00:00:00Z",
|
|
"git_url": "git://github.com/owner/repo.git",
|
|
"ssh_url": "git@github.com:owner/repo.git",
|
|
"clone_url": "https://github.com/owner/repo.git",
|
|
"svn_url": "https://github.com/owner/repo",
|
|
"homepage": null,
|
|
"size": 108,
|
|
"stargazers_count": 0,
|
|
"watchers_count": 0,
|
|
"language": "Go",
|
|
"has_issues": true,
|
|
"has_projects": true,
|
|
"has_wiki": true,
|
|
"has_pages": false,
|
|
"has_downloads": true,
|
|
"archived": false,
|
|
"disabled": false,
|
|
"open_issues_count": 0,
|
|
"license": null,
|
|
"forks_count": 0,
|
|
"open_issues": 0,
|
|
"watchers": 0,
|
|
"default_branch": "main"
|
|
}`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Get repository
|
|
repo, err := client.GetRepository(context.Background(), "owner", "repo")
|
|
if err != nil {
|
|
t.Fatalf("GetRepository failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if repo.Name != "repo" {
|
|
t.Errorf("Expected Name to be 'repo', got '%s'", repo.Name)
|
|
}
|
|
|
|
if repo.FullName != "owner/repo" {
|
|
t.Errorf("Expected FullName to be 'owner/repo', got '%s'", repo.FullName)
|
|
}
|
|
|
|
if repo.Description != "Test repository" {
|
|
t.Errorf("Expected Description to be 'Test repository', got '%s'", repo.Description)
|
|
}
|
|
|
|
if repo.Language != "Go" {
|
|
t.Errorf("Expected Language to be 'Go', got '%s'", repo.Language)
|
|
}
|
|
}
|
|
|
|
func TestGetPullRequest(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodGet {
|
|
t.Errorf("Expected GET request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/repos/owner/repo/pulls/123" {
|
|
t.Errorf("Expected path to be '/repos/owner/repo/pulls/123', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`{
|
|
"id": 1,
|
|
"number": 123,
|
|
"state": "open",
|
|
"title": "Test PR",
|
|
"body": "Test PR body",
|
|
"html_url": "https://github.com/owner/repo/pull/123",
|
|
"user": {
|
|
"login": "testuser",
|
|
"id": 1
|
|
},
|
|
"head": {
|
|
"label": "owner:feature",
|
|
"ref": "feature",
|
|
"sha": "abc123"
|
|
},
|
|
"base": {
|
|
"label": "owner:main",
|
|
"ref": "main",
|
|
"sha": "def456"
|
|
}
|
|
}`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Set repository on client
|
|
client.SetRepository("owner", "repo")
|
|
|
|
// Get pull request
|
|
pullRequest, err := client.GetPullRequest(context.Background(), 123)
|
|
if err != nil {
|
|
t.Fatalf("GetPullRequest failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if pullRequest.ID != 1 {
|
|
t.Errorf("Expected ID to be 1, got %d", pullRequest.ID)
|
|
}
|
|
|
|
if pullRequest.Number != 123 {
|
|
t.Errorf("Expected Number to be 123, got %d", pullRequest.Number)
|
|
}
|
|
|
|
if pullRequest.Title != "Test PR" {
|
|
t.Errorf("Expected Title to be 'Test PR', got '%s'", pullRequest.Title)
|
|
}
|
|
|
|
if pullRequest.Body != "Test PR body" {
|
|
t.Errorf("Expected Body to be 'Test PR body', got '%s'", pullRequest.Body)
|
|
}
|
|
}
|
|
|
|
func TestUpdatePullRequest(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodPatch {
|
|
t.Errorf("Expected PATCH request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/repos/owner/repo/pulls/123" {
|
|
t.Errorf("Expected path to be '/repos/owner/repo/pulls/123', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`{
|
|
"id": 1,
|
|
"number": 123,
|
|
"state": "open",
|
|
"title": "Updated Test PR",
|
|
"body": "Updated Test PR body",
|
|
"html_url": "https://github.com/owner/repo/pull/123",
|
|
"user": {
|
|
"login": "testuser",
|
|
"id": 1
|
|
},
|
|
"head": {
|
|
"label": "owner:feature",
|
|
"ref": "feature",
|
|
"sha": "abc123"
|
|
},
|
|
"base": {
|
|
"label": "owner:main",
|
|
"ref": "main",
|
|
"sha": "def456"
|
|
}
|
|
}`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Set repository on client
|
|
client.SetRepository("owner", "repo")
|
|
|
|
// Update pull request
|
|
pr := &PullRequestRequest{
|
|
Title: "Updated Test PR",
|
|
Body: "Updated Test PR body",
|
|
}
|
|
|
|
pullRequest, err := client.UpdatePullRequest(context.Background(), 123, pr)
|
|
if err != nil {
|
|
t.Fatalf("UpdatePullRequest failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if pullRequest.ID != 1 {
|
|
t.Errorf("Expected ID to be 1, got %d", pullRequest.ID)
|
|
}
|
|
|
|
if pullRequest.Number != 123 {
|
|
t.Errorf("Expected Number to be 123, got %d", pullRequest.Number)
|
|
}
|
|
|
|
if pullRequest.Title != "Updated Test PR" {
|
|
t.Errorf("Expected Title to be 'Updated Test PR', got '%s'", pullRequest.Title)
|
|
}
|
|
|
|
if pullRequest.Body != "Updated Test PR body" {
|
|
t.Errorf("Expected Body to be 'Updated Test PR body', got '%s'", pullRequest.Body)
|
|
}
|
|
}
|
|
|
|
func TestCreateIssue(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodPost {
|
|
t.Errorf("Expected POST request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/repos/owner/repo/issues" {
|
|
t.Errorf("Expected path to be '/repos/owner/repo/issues', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
w.Write([]byte(`{
|
|
"id": 1,
|
|
"number": 123,
|
|
"state": "open",
|
|
"title": "Test Issue",
|
|
"body": "Test Issue body",
|
|
"html_url": "https://github.com/owner/repo/issues/123",
|
|
"user": {
|
|
"login": "testuser",
|
|
"id": 1
|
|
}
|
|
}`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Set repository on client
|
|
client.SetRepository("owner", "repo")
|
|
|
|
// Create issue
|
|
issue := &IssueRequest{
|
|
Title: "Test Issue",
|
|
Body: "Test Issue body",
|
|
}
|
|
|
|
createdIssue, err := client.CreateIssue(context.Background(), issue)
|
|
if err != nil {
|
|
t.Fatalf("CreateIssue failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if createdIssue.ID != 1 {
|
|
t.Errorf("Expected ID to be 1, got %d", createdIssue.ID)
|
|
}
|
|
|
|
if createdIssue.Number != 123 {
|
|
t.Errorf("Expected Number to be 123, got %d", createdIssue.Number)
|
|
}
|
|
|
|
if createdIssue.Title != "Test Issue" {
|
|
t.Errorf("Expected Title to be 'Test Issue', got '%s'", createdIssue.Title)
|
|
}
|
|
|
|
if createdIssue.Body != "Test Issue body" {
|
|
t.Errorf("Expected Body to be 'Test Issue body', got '%s'", createdIssue.Body)
|
|
}
|
|
}
|
|
|
|
func TestGetIssues(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodGet {
|
|
t.Errorf("Expected GET request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/repos/owner/repo/issues" {
|
|
t.Errorf("Expected path to be '/repos/owner/repo/issues', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check request query
|
|
if r.URL.Query().Get("state") != "open" {
|
|
t.Errorf("Expected state query to be 'open', got '%s'", r.URL.Query().Get("state"))
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`[
|
|
{
|
|
"id": 1,
|
|
"number": 123,
|
|
"state": "open",
|
|
"title": "Test Issue 1",
|
|
"body": "Test Issue body 1",
|
|
"html_url": "https://github.com/owner/repo/issues/123",
|
|
"user": {
|
|
"login": "testuser",
|
|
"id": 1
|
|
}
|
|
},
|
|
{
|
|
"id": 2,
|
|
"number": 124,
|
|
"state": "open",
|
|
"title": "Test Issue 2",
|
|
"body": "Test Issue body 2",
|
|
"html_url": "https://github.com/owner/repo/issues/124",
|
|
"user": {
|
|
"login": "testuser",
|
|
"id": 1
|
|
}
|
|
}
|
|
]`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Set repository on client
|
|
client.SetRepository("owner", "repo")
|
|
|
|
// Get issues
|
|
issues, err := client.GetIssues(context.Background(), "open")
|
|
if err != nil {
|
|
t.Fatalf("GetIssues failed: %v", err)
|
|
}
|
|
|
|
// Check response
|
|
if len(issues) != 2 {
|
|
t.Errorf("Expected 2 issues, got %d", len(issues))
|
|
}
|
|
|
|
if issues[0].ID != 1 {
|
|
t.Errorf("Expected first issue ID to be 1, got %d", issues[0].ID)
|
|
}
|
|
|
|
if issues[0].Number != 123 {
|
|
t.Errorf("Expected first issue Number to be 123, got %d", issues[0].Number)
|
|
}
|
|
|
|
if issues[0].Title != "Test Issue 1" {
|
|
t.Errorf("Expected first issue Title to be 'Test Issue 1', got '%s'", issues[0].Title)
|
|
}
|
|
|
|
if issues[1].ID != 2 {
|
|
t.Errorf("Expected second issue ID to be 2, got %d", issues[1].ID)
|
|
}
|
|
|
|
if issues[1].Number != 124 {
|
|
t.Errorf("Expected second issue Number to be 124, got %d", issues[1].Number)
|
|
}
|
|
|
|
if issues[1].Title != "Test Issue 2" {
|
|
t.Errorf("Expected second issue Title to be 'Test Issue 2', got '%s'", issues[1].Title)
|
|
}
|
|
}
|
|
|
|
func TestValidateToken(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// Check request method
|
|
if r.Method != http.MethodGet {
|
|
t.Errorf("Expected GET request, got %s", r.Method)
|
|
}
|
|
|
|
// Check request path
|
|
if r.URL.Path != "/user" {
|
|
t.Errorf("Expected path to be '/user', got '%s'", r.URL.Path)
|
|
}
|
|
|
|
// Check authorization header
|
|
if r.Header.Get("Authorization") != "token test-token" {
|
|
t.Errorf("Expected Authorization header to be 'token test-token', got '%s'", r.Header.Get("Authorization"))
|
|
}
|
|
|
|
// Write response
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`{
|
|
"login": "testuser",
|
|
"id": 1
|
|
}`))
|
|
})
|
|
defer server.Close()
|
|
|
|
// Validate token
|
|
err := client.ValidateToken(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("ValidateToken failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetRepositoryFromRemote(t *testing.T) {
|
|
// Create a test server
|
|
server, client := setupTestServer(t, func(w http.ResponseWriter, r *http.Request) {
|
|
// This function doesn't make HTTP requests, so we don't need to check anything
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
defer server.Close()
|
|
|
|
// Get repository from remote
|
|
owner, repo, err := client.GetRepositoryFromRemote(context.Background(), "origin")
|
|
if err == nil {
|
|
t.Error("Expected GetRepositoryFromRemote to return an error, got nil")
|
|
}
|
|
|
|
if owner != "" {
|
|
t.Errorf("Expected owner to be empty, got '%s'", owner)
|
|
}
|
|
|
|
if repo != "" {
|
|
t.Errorf("Expected repo to be empty, got '%s'", repo)
|
|
}
|
|
} |