1
2
3 package repository
4
5 import (
6 "errors"
7 "fmt"
8 "os"
9 "strings"
10
11 "github.com/cli/go-gh/v2/internal/git"
12 "github.com/cli/go-gh/v2/pkg/auth"
13 "github.com/cli/go-gh/v2/pkg/ssh"
14 )
15
16
17 type Repository struct {
18 Host string
19 Name string
20 Owner string
21 }
22
23
24
25
26 func Parse(s string) (Repository, error) {
27 var r Repository
28
29 if git.IsURL(s) {
30 u, err := git.ParseURL(s)
31 if err != nil {
32 return r, err
33 }
34
35 host, owner, name, err := git.RepoInfoFromURL(u)
36 if err != nil {
37 return r, err
38 }
39
40 r.Host = host
41 r.Name = name
42 r.Owner = owner
43
44 return r, nil
45 }
46
47 parts := strings.SplitN(s, "/", 4)
48 for _, p := range parts {
49 if len(p) == 0 {
50 return r, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, s)
51 }
52 }
53
54 switch len(parts) {
55 case 3:
56 r.Host = parts[0]
57 r.Owner = parts[1]
58 r.Name = parts[2]
59 return r, nil
60 case 2:
61 r.Host, _ = auth.DefaultHost()
62 r.Owner = parts[0]
63 r.Name = parts[1]
64 return r, nil
65 default:
66 return r, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, s)
67 }
68 }
69
70
71
72
73 func ParseWithHost(s, host string) (Repository, error) {
74 var r Repository
75
76 if git.IsURL(s) {
77 u, err := git.ParseURL(s)
78 if err != nil {
79 return r, err
80 }
81
82 host, owner, name, err := git.RepoInfoFromURL(u)
83 if err != nil {
84 return r, err
85 }
86
87 r.Host = host
88 r.Owner = owner
89 r.Name = name
90
91 return r, nil
92 }
93
94 parts := strings.SplitN(s, "/", 4)
95 for _, p := range parts {
96 if len(p) == 0 {
97 return r, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, s)
98 }
99 }
100
101 switch len(parts) {
102 case 3:
103 r.Host = parts[0]
104 r.Owner = parts[1]
105 r.Name = parts[2]
106 return r, nil
107 case 2:
108 r.Host = host
109 r.Owner = parts[0]
110 r.Name = parts[1]
111 return r, nil
112 default:
113 return r, fmt.Errorf(`expected the "[HOST/]OWNER/REPO" format, got %q`, s)
114 }
115 }
116
117
118
119 func Current() (Repository, error) {
120 var r Repository
121
122 override := os.Getenv("GH_REPO")
123 if override != "" {
124 return Parse(override)
125 }
126
127 remotes, err := git.Remotes()
128 if err != nil {
129 return r, err
130 }
131 if len(remotes) == 0 {
132 return r, errors.New("unable to determine current repository, no git remotes configured for this repository")
133 }
134
135 translator := ssh.NewTranslator()
136 for _, r := range remotes {
137 if r.FetchURL != nil {
138 r.FetchURL = translator.Translate(r.FetchURL)
139 }
140 if r.PushURL != nil {
141 r.PushURL = translator.Translate(r.PushURL)
142 }
143 }
144
145 hosts := auth.KnownHosts()
146
147 filteredRemotes := remotes.FilterByHosts(hosts)
148 if len(filteredRemotes) == 0 {
149 return r, errors.New("unable to determine current repository, none of the git remotes configured for this repository point to a known GitHub host")
150 }
151
152 rem := filteredRemotes[0]
153 r.Host = rem.Host
154 r.Owner = rem.Owner
155 r.Name = rem.Repo
156
157 return r, nil
158 }
159
View as plain text