-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgithub.go
More file actions
127 lines (112 loc) · 3.57 KB
/
github.go
File metadata and controls
127 lines (112 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package devflow
import (
"fmt"
"strings"
)
// GitHub handler for GitHub operations
type GitHub struct {
log func(...any)
SecretRunner SecretRunner
}
// NewGitHub creates handler and verifies gh CLI availability.
// logFn is used to display authentication messages during Device Flow.
// If not authenticated, it initiates OAuth Device Flow automatically.
func NewGitHub(logFn func(...any), auth ...GitHubAuthenticator) (*GitHub, error) {
if logFn == nil {
logFn = func(...any) {}
}
gh := &GitHub{
log: logFn,
}
// Verify gh installation
if _, err := RunCommandSilent("gh", "--version"); err != nil {
return nil, fmt.Errorf("gh cli is not installed or not in PATH: %w", err)
}
// Ensure authentication - this will initiate Device Flow if needed
var authenticator GitHubAuthenticator
if len(auth) > 0 && auth[0] != nil {
// Use injected authenticator (already has TUI logger set)
authenticator = auth[0]
} else {
// Create default authenticator and set logger
authenticator = NewGitHubAuth()
authenticator.SetLog(gh.log)
}
if err := authenticator.EnsureGitHubAuth(); err != nil {
return nil, fmt.Errorf("github authentication failed: %w", err)
}
return gh, nil
}
// SetLog sets the logger function
func (gh *GitHub) SetLog(fn func(...any)) {
if fn != nil {
gh.log = fn
}
}
// GetCurrentUser gets the current authenticated user
func (gh *GitHub) GetCurrentUser() (string, error) {
output, err := RunCommandSilent("gh", "api", "user", "--jq", ".login")
if err != nil {
return "", fmt.Errorf("failed to get current user: %w", err)
}
return strings.TrimSpace(output), nil
}
// RepoExists checks if a repository exists
func (gh *GitHub) RepoExists(owner, name string) (bool, error) {
// gh repo view owner/name
_, err := RunCommandSilent("gh", "repo", "view", fmt.Sprintf("%s/%s", owner, name))
if err != nil {
return false, nil
}
return true, nil
}
// CreateRepo creates a new empty repository on GitHub
// If owner is provided, creates repo under that organization
func (gh *GitHub) CreateRepo(owner, name, description, visibility string) error {
repoName := name
if owner != "" {
repoName = fmt.Sprintf("%s/%s", owner, name)
}
// Create empty repo without --source or --push (will add remote and push manually)
args := []string{"repo", "create", repoName, "--description", description}
if visibility == "private" {
args = append(args, "--private")
} else {
args = append(args, "--public")
}
_, err := RunCommand("gh", args...)
return err
}
// DeleteRepo deletes a repository on GitHub.
// WARNING: This permanently deletes the repository and cannot be undone.
// Use with caution, primarily for test cleanup.
func (gh *GitHub) DeleteRepo(owner, name string) error {
repoName := fmt.Sprintf("%s/%s", owner, name)
// --yes confirms deletion without prompting
_, err := RunCommand("gh", "repo", "delete", repoName, "--yes")
return err
}
// IsNetworkError checks if an error is likely a network error
func (gh *GitHub) IsNetworkError(err error) bool {
if err == nil {
return false
}
msg := err.Error()
return strings.Contains(msg, "dial tcp") ||
strings.Contains(msg, "connection refused") ||
strings.Contains(msg, "no such host") ||
strings.Contains(msg, "timeout")
}
// GetHelpfulErrorMessage returns a helpful message for common errors
func (gh *GitHub) GetHelpfulErrorMessage(err error) string {
if err == nil {
return ""
}
if gh.IsNetworkError(err) {
return "Network error. Check your internet connection."
}
if strings.Contains(err.Error(), "authentication") {
return "Authentication failed. Run 'gh auth login'."
}
return err.Error()
}