(statusCode int, endpointNeedsScopes, tokenHasScopes, hostname string)
| 207 | } |
| 208 | |
| 209 | func generateScopesSuggestion(statusCode int, endpointNeedsScopes, tokenHasScopes, hostname string) string { |
| 210 | if statusCode < 400 || statusCode > 499 || statusCode == 422 { |
| 211 | return "" |
| 212 | } |
| 213 | |
| 214 | if tokenHasScopes == "" { |
| 215 | return "" |
| 216 | } |
| 217 | |
| 218 | gotScopes := map[string]struct{}{} |
| 219 | for _, s := range strings.Split(tokenHasScopes, ",") { |
| 220 | s = strings.TrimSpace(s) |
| 221 | gotScopes[s] = struct{}{} |
| 222 | |
| 223 | // Certain scopes may be grouped under a single "top-level" scope. The following branch |
| 224 | // statements include these grouped/implied scopes when the top-level scope is encountered. |
| 225 | // See https://docs.github.com/en/developers/apps/building-oauth-apps/scopes-for-oauth-apps. |
| 226 | if s == "repo" { |
| 227 | gotScopes["repo:status"] = struct{}{} |
| 228 | gotScopes["repo_deployment"] = struct{}{} |
| 229 | gotScopes["public_repo"] = struct{}{} |
| 230 | gotScopes["repo:invite"] = struct{}{} |
| 231 | gotScopes["security_events"] = struct{}{} |
| 232 | } else if s == "user" { |
| 233 | gotScopes["read:user"] = struct{}{} |
| 234 | gotScopes["user:email"] = struct{}{} |
| 235 | gotScopes["user:follow"] = struct{}{} |
| 236 | } else if s == "codespace" { |
| 237 | gotScopes["codespace:secrets"] = struct{}{} |
| 238 | } else if strings.HasPrefix(s, "admin:") { |
| 239 | gotScopes["read:"+strings.TrimPrefix(s, "admin:")] = struct{}{} |
| 240 | gotScopes["write:"+strings.TrimPrefix(s, "admin:")] = struct{}{} |
| 241 | } else if strings.HasPrefix(s, "write:") { |
| 242 | gotScopes["read:"+strings.TrimPrefix(s, "write:")] = struct{}{} |
| 243 | } |
| 244 | } |
| 245 | |
| 246 | for _, s := range strings.Split(endpointNeedsScopes, ",") { |
| 247 | s = strings.TrimSpace(s) |
| 248 | if _, gotScope := gotScopes[s]; s == "" || gotScope { |
| 249 | continue |
| 250 | } |
| 251 | return fmt.Sprintf( |
| 252 | "This API operation needs the %[1]q scope. To request it, run: gh auth refresh -h %[2]s -s %[1]s", |
| 253 | s, |
| 254 | ghauth.NormalizeHostname(hostname), |
| 255 | ) |
| 256 | } |
| 257 | |
| 258 | return "" |
| 259 | } |
| 260 | |
| 261 | func clientOptions(hostname string, transport http.RoundTripper) ghAPI.ClientOptions { |
| 262 | // AuthToken, and Headers are being handled by transport, |
no outgoing calls
no test coverage detected