Skip to content

Commit 52ee643

Browse files
authored
Merge pull request #15 from codeGROOVE-dev/others
more API refactoring work
2 parents 587c100 + eadb38b commit 52ee643

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1362
-3276
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ Go library for fetching pull request data from GitHub, GitLab, and Gitea/Codeber
55
## Quick Start
66

77
```go
8-
import "github.com/codeGROOVE-dev/prx/pkg/prx"
8+
import "github.com/codeGROOVE-dev/prx/pkg/pr"
99

10-
data, err := prx.Fetch(ctx, "https://github.com/golang/go/pull/12345")
10+
data, err := pr.Fetch(ctx, "https://github.com/golang/go/pull/12345")
1111
// Works with: GitHub, GitLab, Codeberg, self-hosted instances
1212
```
1313
Auto-detects platform and resolves authentication from `GITHUB_TOKEN`/`GITLAB_TOKEN`/`GITEA_TOKEN` or CLI tools (`gh`, `glab`, `tea`, `berg`).
@@ -21,7 +21,7 @@ import (
2121
)
2222

2323
platform := github.NewPlatform(token)
24-
client := prx.NewClientWithPlatform(platform)
24+
client := prx.NewClient(platform)
2525
data, err := client.PullRequest(ctx, "owner", "repo", 123)
2626
```
2727

cmd/prx/main.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"github.com/codeGROOVE-dev/prx/pkg/prx/gitea"
1919
"github.com/codeGROOVE-dev/prx/pkg/prx/github"
2020
"github.com/codeGROOVE-dev/prx/pkg/prx/gitlab"
21-
"github.com/codeGROOVE-dev/prx/pkg/prx/types"
2221
)
2322

2423
var (
@@ -60,7 +59,7 @@ func run() error {
6059

6160
prURL := flag.Arg(0)
6261

63-
parsed, err := types.ParseURL(prURL)
62+
parsed, err := prx.ParseURL(prURL)
6463
if err != nil {
6564
return fmt.Errorf("invalid PR URL: %w", err)
6665
}
@@ -75,7 +74,7 @@ func run() error {
7574
token, err := resolver.Resolve(ctx, platform, parsed.Host)
7675
// Authentication is optional for public repos on GitLab/Gitea/Codeberg
7776
// Only GitHub strictly requires authentication for most API calls
78-
tokenOptional := parsed.Platform != types.PlatformGitHub
77+
tokenOptional := parsed.Platform != prx.PlatformGitHub
7978

8079
if err != nil && !tokenOptional {
8180
return fmt.Errorf("authentication failed: %w", err)
@@ -90,13 +89,13 @@ func run() error {
9089
}
9190

9291
// Create platform-specific client
93-
var prxPlatform types.Platform
92+
var prxPlatform prx.Platform
9493
switch parsed.Platform {
95-
case types.PlatformGitHub:
94+
case prx.PlatformGitHub:
9695
prxPlatform = github.NewPlatform(tokenValue)
97-
case types.PlatformGitLab:
96+
case prx.PlatformGitLab:
9897
prxPlatform = gitlab.NewPlatform(tokenValue, gitlab.WithBaseURL("https://"+parsed.Host))
99-
case types.PlatformCodeberg:
98+
case prx.PlatformCodeberg:
10099
prxPlatform = gitea.NewCodebergPlatform(tokenValue)
101100
default:
102101
// Self-hosted Gitea
@@ -109,10 +108,10 @@ func run() error {
109108
opts = append(opts, prx.WithLogger(slog.Default()))
110109
}
111110
if *noCache {
112-
opts = append(opts, prx.WithCacheStore(null.New[string, types.PullRequestData]()))
111+
opts = append(opts, prx.WithCacheStore(null.New[string, prx.PullRequestData]()))
113112
}
114113

115-
client := prx.NewClientWithPlatform(prxPlatform, opts...)
114+
client := prx.NewClient(prxPlatform, opts...)
116115
data, err := client.PullRequestWithReferenceTime(ctx, parsed.Owner, parsed.Repo, parsed.Number, referenceTime)
117116
if err != nil {
118117
return fmt.Errorf("failed to fetch PR data: %w", err)

cmd/prx_compare/main.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414

1515
"github.com/codeGROOVE-dev/prx/pkg/prx"
1616
"github.com/codeGROOVE-dev/prx/pkg/prx/github"
17-
"github.com/codeGROOVE-dev/prx/pkg/prx/types"
1817
)
1918

2019
const (
@@ -40,15 +39,15 @@ func main() {
4039

4140
// Both now use GraphQL, but we'll compare two fetches to ensure consistency
4241
fmt.Println("Fetching first time...")
43-
restClient := prx.NewClientWithPlatform(github.NewPlatform(token))
42+
restClient := prx.NewClient(github.NewPlatform(token))
4443
restData, err := restClient.PullRequest(context.TODO(), owner, repo, prNumber)
4544
if err != nil {
4645
log.Fatalf("First fetch failed: %v", err)
4746
}
4847

4948
// Fetch again to compare consistency
5049
fmt.Println("Fetching second time...")
51-
graphqlClient := prx.NewClientWithPlatform(github.NewPlatform(token))
50+
graphqlClient := prx.NewClient(github.NewPlatform(token))
5251
graphqlData, err := graphqlClient.PullRequest(context.TODO(), owner, repo, prNumber)
5352
if err != nil {
5453
log.Fatalf("Second fetch failed: %v", err)
@@ -64,7 +63,7 @@ func main() {
6463
fmt.Println("\nFull data saved to rest_output.json and graphql_output.json")
6564
}
6665

67-
func comparePullRequestData(rest, graphql *types.PullRequestData) {
66+
func comparePullRequestData(rest, graphql *prx.PullRequestData) {
6867
// Compare PullRequest fields
6968
fmt.Println("=== Pull Request Metadata ===")
7069
comparePullRequest(&rest.PullRequest, &graphql.PullRequest)
@@ -74,7 +73,7 @@ func comparePullRequestData(rest, graphql *types.PullRequestData) {
7473
compareEvents(rest.Events, graphql.Events)
7574
}
7675

77-
func comparePullRequest(rest, graphql *types.PullRequest) {
76+
func comparePullRequest(rest, graphql *prx.PullRequest) {
7877
differences, matches := compareFields(rest, graphql)
7978

8079
if len(differences) > 0 {
@@ -87,7 +86,7 @@ func comparePullRequest(rest, graphql *types.PullRequest) {
8786
fmt.Printf("\nMatching fields: %s\n", strings.Join(matches, ", "))
8887
}
8988

90-
func compareFields(rest, graphql *types.PullRequest) (differences, matches []string) {
89+
func compareFields(rest, graphql *prx.PullRequest) (differences, matches []string) {
9190
restVal := reflect.ValueOf(*rest)
9291
graphqlVal := reflect.ValueOf(*graphql)
9392
restType := restVal.Type()
@@ -132,7 +131,7 @@ func comparePointerField(name string, restField, graphqlField reflect.Value) str
132131
return ""
133132
}
134133

135-
func compareCheckSummary(rest, graphql *types.PullRequest) {
134+
func compareCheckSummary(rest, graphql *prx.PullRequest) {
136135
if rest.CheckSummary == nil || graphql.CheckSummary == nil {
137136
return
138137
}
@@ -150,7 +149,7 @@ func compareCheckSummary(rest, graphql *types.PullRequest) {
150149
compareCheckSummaryMaps(rest.CheckSummary, graphql.CheckSummary)
151150
}
152151

153-
func compareCheckSummaryMaps(rest, graphql *types.CheckSummary) {
152+
func compareCheckSummaryMaps(rest, graphql *prx.CheckSummary) {
154153
compareSummaryMap("Success", rest.Success, graphql.Success)
155154
compareSummaryMap("Failing", rest.Failing, graphql.Failing)
156155
compareSummaryMap("Pending", rest.Pending, graphql.Pending)
@@ -187,7 +186,7 @@ func compareStatusMaps(rest, graphql map[string]string) {
187186
}
188187
}
189188

190-
func compareEvents(restEvents, graphqlEvents []types.Event) {
189+
func compareEvents(restEvents, graphqlEvents []prx.Event) {
191190
// Count events by type
192191
restCounts := countEventsByType(restEvents)
193192
graphqlCounts := countEventsByType(graphqlEvents)
@@ -295,23 +294,23 @@ func compareEvents(restEvents, graphqlEvents []types.Event) {
295294
}
296295
}
297296

298-
func countEventsByType(events []types.Event) map[string]int {
297+
func countEventsByType(events []prx.Event) map[string]int {
299298
counts := make(map[string]int)
300299
for i := range events {
301300
counts[events[i].Kind]++
302301
}
303302
return counts
304303
}
305304

306-
func groupEventsByType(events []types.Event) map[string][]types.Event {
307-
grouped := make(map[string][]types.Event)
305+
func groupEventsByType(events []prx.Event) map[string][]prx.Event {
306+
grouped := make(map[string][]prx.Event)
308307
for i := range events {
309308
grouped[events[i].Kind] = append(grouped[events[i].Kind], events[i])
310309
}
311310
return grouped
312311
}
313312

314-
func extractWriteAccess(events []types.Event) map[string]int {
313+
func extractWriteAccess(events []prx.Event) map[string]int {
315314
access := make(map[string]int)
316315
for i := range events {
317316
e := &events[i]
@@ -325,7 +324,7 @@ func extractWriteAccess(events []types.Event) map[string]int {
325324
return access
326325
}
327326

328-
func extractBots(events []types.Event) map[string]bool {
327+
func extractBots(events []prx.Event) map[string]bool {
329328
bots := make(map[string]bool)
330329
for i := range events {
331330
e := &events[i]

pkg/prx/auth/auth_test.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,3 +490,177 @@ func TestResolver_ResolveGitea_TeaConfig(t *testing.T) {
490490
t.Errorf("Source = %v, want %v", token.Source, TokenSourceConfig)
491491
}
492492
}
493+
494+
func TestResolver_ResolveGitHub_NoToken(t *testing.T) {
495+
// Clear all env vars
496+
os.Unsetenv("GITHUB_TOKEN")
497+
os.Unsetenv("GH_TOKEN")
498+
499+
// Set PATH to empty to ensure gh CLI is not available
500+
oldPath := os.Getenv("PATH")
501+
defer os.Setenv("PATH", oldPath)
502+
os.Setenv("PATH", "")
503+
504+
resolver := NewResolver()
505+
_, err := resolver.ResolveGitHub(context.Background())
506+
if err == nil {
507+
t.Error("Expected error when no GitHub token available")
508+
}
509+
}
510+
511+
func TestResolver_ResolveGitLab_NoToken(t *testing.T) {
512+
// Clear all env vars
513+
os.Unsetenv("GITLAB_TOKEN")
514+
os.Unsetenv("GL_TOKEN")
515+
516+
// Set PATH to empty to ensure glab CLI is not available
517+
oldPath := os.Getenv("PATH")
518+
defer os.Setenv("PATH", oldPath)
519+
os.Setenv("PATH", "")
520+
521+
resolver := NewResolver()
522+
_, err := resolver.ResolveGitLab(context.Background(), "")
523+
if err == nil {
524+
t.Error("Expected error when no GitLab token available")
525+
}
526+
}
527+
528+
func TestResolver_ResolveGitHub_EmptyEnvVar(t *testing.T) {
529+
// Set env var to empty string
530+
t.Setenv("GITHUB_TOKEN", "")
531+
t.Setenv("GH_TOKEN", "")
532+
533+
// Set PATH to empty to ensure gh CLI is not available
534+
oldPath := os.Getenv("PATH")
535+
defer os.Setenv("PATH", oldPath)
536+
os.Setenv("PATH", "")
537+
538+
resolver := NewResolver()
539+
_, err := resolver.ResolveGitHub(context.Background())
540+
if err == nil {
541+
t.Error("Expected error when GitHub token env var is empty")
542+
}
543+
}
544+
545+
func TestResolver_ResolveGitLab_EmptyEnvVar(t *testing.T) {
546+
// Set env var to empty string
547+
t.Setenv("GITLAB_TOKEN", "")
548+
t.Setenv("GL_TOKEN", "")
549+
550+
// Set PATH to empty to ensure glab CLI is not available
551+
oldPath := os.Getenv("PATH")
552+
defer os.Setenv("PATH", oldPath)
553+
os.Setenv("PATH", "")
554+
555+
resolver := NewResolver()
556+
_, err := resolver.ResolveGitLab(context.Background(), "gitlab.com")
557+
if err == nil {
558+
t.Error("Expected error when GitLab token env var is empty")
559+
}
560+
}
561+
562+
func TestResolver_ResolveGitea_EmptyEnvVar(t *testing.T) {
563+
// Set env vars to empty strings
564+
t.Setenv("CODEBERG_TOKEN", "")
565+
t.Setenv("GITEA_TOKEN", "")
566+
567+
resolver := NewResolver()
568+
_, err := resolver.ResolveGitea(context.Background(), "codeberg.org")
569+
if err == nil {
570+
t.Error("Expected error when Gitea token env var is empty")
571+
}
572+
}
573+
574+
func TestResolver_ResolveGitLab_CLISuccess(t *testing.T) {
575+
// Clear env vars to force CLI path
576+
os.Unsetenv("GITLAB_TOKEN")
577+
os.Unsetenv("GL_TOKEN")
578+
579+
// Create a mock glab command that returns a token
580+
tempDir := t.TempDir()
581+
glabScript := filepath.Join(tempDir, "glab")
582+
scriptContent := `#!/bin/sh
583+
echo "glpat_cli_token"
584+
`
585+
if err := os.WriteFile(glabScript, []byte(scriptContent), 0o755); err != nil {
586+
t.Fatalf("Failed to create mock glab script: %v", err)
587+
}
588+
589+
// Prepend our temp dir to PATH
590+
oldPath := os.Getenv("PATH")
591+
t.Setenv("PATH", tempDir+":"+oldPath)
592+
593+
resolver := NewResolver()
594+
token, err := resolver.ResolveGitLab(context.Background(), "gitlab.com")
595+
if err != nil {
596+
t.Errorf("Unexpected error: %v", err)
597+
return
598+
}
599+
600+
if token.Value != "glpat_cli_token" {
601+
t.Errorf("Token = %q, want %q", token.Value, "glpat_cli_token")
602+
}
603+
if token.Source != TokenSourceCLI {
604+
t.Errorf("Source = %v, want %v", token.Source, TokenSourceCLI)
605+
}
606+
}
607+
608+
func TestResolver_ResolveGitHub_CLISuccess(t *testing.T) {
609+
// Clear env vars to force CLI path
610+
os.Unsetenv("GITHUB_TOKEN")
611+
os.Unsetenv("GH_TOKEN")
612+
613+
// Create a mock gh command that returns a token
614+
tempDir := t.TempDir()
615+
ghScript := filepath.Join(tempDir, "gh")
616+
scriptContent := `#!/bin/sh
617+
echo "ghp_cli_token"
618+
`
619+
if err := os.WriteFile(ghScript, []byte(scriptContent), 0o755); err != nil {
620+
t.Fatalf("Failed to create mock gh script: %v", err)
621+
}
622+
623+
// Prepend our temp dir to PATH
624+
oldPath := os.Getenv("PATH")
625+
t.Setenv("PATH", tempDir+":"+oldPath)
626+
627+
resolver := NewResolver()
628+
token, err := resolver.ResolveGitHub(context.Background())
629+
if err != nil {
630+
t.Errorf("Unexpected error: %v", err)
631+
return
632+
}
633+
634+
if token.Value != "ghp_cli_token" {
635+
t.Errorf("Token = %q, want %q", token.Value, "ghp_cli_token")
636+
}
637+
if token.Source != TokenSourceCLI {
638+
t.Errorf("Source = %v, want %v", token.Source, TokenSourceCLI)
639+
}
640+
}
641+
642+
func TestResolver_ResolveGitLab_CLIEmptyToken(t *testing.T) {
643+
// Clear env vars to force CLI path
644+
os.Unsetenv("GITLAB_TOKEN")
645+
os.Unsetenv("GL_TOKEN")
646+
647+
// Create a mock glab command that returns empty
648+
tempDir := t.TempDir()
649+
glabScript := filepath.Join(tempDir, "glab")
650+
scriptContent := `#!/bin/sh
651+
echo ""
652+
`
653+
if err := os.WriteFile(glabScript, []byte(scriptContent), 0o755); err != nil {
654+
t.Fatalf("Failed to create mock glab script: %v", err)
655+
}
656+
657+
// Prepend our temp dir to PATH
658+
oldPath := os.Getenv("PATH")
659+
t.Setenv("PATH", tempDir+":"+oldPath)
660+
661+
resolver := NewResolver()
662+
_, err := resolver.ResolveGitLab(context.Background(), "gitlab.com")
663+
if err == nil {
664+
t.Error("Expected error when glab returns empty token")
665+
}
666+
}

0 commit comments

Comments
 (0)