mirror of
https://github.com/Graylog2/graylog-project-cli.git
synced 2026-03-13 08:02:57 +08:00
191 lines
5.7 KiB
Go
191 lines
5.7 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/pkg/errors"
|
|
neturl "net/url"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func ParseGitHubURL(url string) (GitHubURL, error) {
|
|
if !strings.HasSuffix(url, ".git") {
|
|
return GitHubURL{}, errors.Errorf("GitHub URL is missing .git suffix: %s", url)
|
|
}
|
|
|
|
var repository string
|
|
switch {
|
|
case strings.HasPrefix(url, "github://"):
|
|
repository = strings.Split(url, "//")[1]
|
|
case strings.HasPrefix(url, "git@github"):
|
|
repository = strings.Split(url, ":")[1]
|
|
case strings.HasPrefix(url, "https://"):
|
|
repository = strings.Split(url, "github.com/")[1]
|
|
default:
|
|
return GitHubURL{}, errors.Errorf("unknown GitHub URL: %s", url)
|
|
}
|
|
|
|
return CreateGitHubURL(url, repository)
|
|
}
|
|
|
|
func ParseGitHubPRString(prString string) (string, int, error) {
|
|
pattern := regexp.MustCompile("^[\\w-_.]+/[\\w-_.]+#\\d+$")
|
|
|
|
var parts []string
|
|
|
|
if strings.HasPrefix(strings.ToLower(prString), "https://github.com/") && strings.Contains(prString, "/pull/") {
|
|
// Input is a PR URL like this: https://github.com/Graylog2/graylog2-server/pull/9692
|
|
u, err := neturl.Parse(prString)
|
|
if err != nil {
|
|
return "", 0, errors.Wrapf(err, "couldn't parse GitHub pull request URL <%s>", prString)
|
|
}
|
|
parts = strings.SplitN(strings.TrimPrefix(u.Path, "/"), "/pull/", 2)
|
|
} else if pattern.MatchString(prString) {
|
|
// Input is "<owner>/<repo>#<pr-num>" (e.g. Graylog2/graylog2-server#123)
|
|
parts = strings.SplitN(prString, "#", 2)
|
|
} else {
|
|
return "", 0, errors.Errorf("unknown GitHub pull request string <%s>", prString)
|
|
}
|
|
|
|
if len(parts) != 2 {
|
|
return "", 0, errors.Errorf("couldn't extract pull request repo and number from <%s> (%v)", prString, parts)
|
|
}
|
|
|
|
prRepo := parts[0]
|
|
if prRepo == "" {
|
|
return "", 0, errors.Errorf("couldn't parse pull request repository from <%s>", prString)
|
|
}
|
|
prNumber, err := strconv.Atoi(parts[1])
|
|
if err != nil {
|
|
return "", 0, errors.Errorf("couldn't parse pull request number from <%s>", prString)
|
|
}
|
|
|
|
return prRepo, prNumber, nil
|
|
}
|
|
|
|
func ResolveGitHubIssueURL(baseRepo string, issueString string) (string, error) {
|
|
repo := strings.TrimSuffix(baseRepo, ".git")
|
|
fullURLPattern := regexp.MustCompile("^https://github\\.com/[^/]+/[^/]+/(?:issues|pull)/\\d+$")
|
|
numPattern := regexp.MustCompile("^#?(\\d+)$")
|
|
repoNamePattern := regexp.MustCompile("^([^/\\s]+)#(\\d+)$")
|
|
orgRepoNamePattern := regexp.MustCompile("^([^/\\s]+)/([^/\\s]+)#(\\d+)$")
|
|
|
|
if fullURLPattern.FindStringSubmatch(issueString) != nil {
|
|
return issueString, nil
|
|
}
|
|
if matches := numPattern.FindStringSubmatch(issueString); matches != nil {
|
|
return repo + "/issues/" + matches[1], nil
|
|
}
|
|
if matches := repoNamePattern.FindStringSubmatch(issueString); matches != nil {
|
|
org := strings.Split(strings.TrimPrefix(repo, "https://github.com/"), "/")[0]
|
|
return "https://github.com/" + org + "/" + matches[1] + "/issues/" + matches[2], nil
|
|
}
|
|
if matches := orgRepoNamePattern.FindStringSubmatch(issueString); matches != nil {
|
|
return "https://github.com/" + matches[1] + "/" + matches[2] + "/issues/" + matches[3], nil
|
|
}
|
|
|
|
return "", fmt.Errorf("couldn't parse issue string \"%s\" for repository \"%s\"", issueString, baseRepo)
|
|
}
|
|
|
|
type PrettyMode int
|
|
|
|
const (
|
|
PrettyModeNum PrettyMode = iota
|
|
PrettyModeRepo
|
|
PrettyModeOrgRepo
|
|
)
|
|
|
|
func PrettifyGitHubIssueURL(githubURL string, mode PrettyMode) string {
|
|
pattern := regexp.MustCompile("^https://github\\.com/([^/]+)/([^/]+)/(?:issues|pull)/(\\d+)$")
|
|
match := pattern.FindStringSubmatch(githubURL)
|
|
|
|
switch mode {
|
|
case PrettyModeNum:
|
|
return fmt.Sprintf("#%s", match[3])
|
|
case PrettyModeRepo:
|
|
return fmt.Sprintf("%s#%s", match[2], match[3])
|
|
case PrettyModeOrgRepo:
|
|
fallthrough
|
|
default:
|
|
return fmt.Sprintf("%s/%s#%s", match[1], match[2], match[3])
|
|
}
|
|
}
|
|
|
|
func ReplaceGitHubURL(url string, repoName string) (string, error) {
|
|
name := strings.TrimSuffix(repoName, ".git")
|
|
|
|
switch {
|
|
case strings.HasPrefix(url, "github://"):
|
|
return fmt.Sprintf("github://%s.git", name), nil
|
|
case strings.HasPrefix(url, "git@github"):
|
|
return fmt.Sprintf("git@github.com:%s.git", name), nil
|
|
case strings.HasPrefix(url, "https://github"):
|
|
return fmt.Sprintf("https://github.com/%s.git", name), nil
|
|
default:
|
|
return "", errors.Errorf("unknown GitHub URL: %s", url)
|
|
}
|
|
}
|
|
|
|
func CreateGitHubURL(url string, repository string) (GitHubURL, error) {
|
|
if url == "" || repository == "" {
|
|
return GitHubURL{}, fmt.Errorf("url and repository cannot be empty")
|
|
}
|
|
if strings.HasPrefix(url, "https://") {
|
|
u, err := neturl.Parse(url)
|
|
if err != nil {
|
|
return GitHubURL{}, fmt.Errorf("couldn't parse URL: %s", err)
|
|
}
|
|
u.User = nil
|
|
return GitHubURL{url: u.Redacted(), repository: repository}, nil
|
|
}
|
|
return GitHubURL{url: url, repository: repository}, nil
|
|
}
|
|
|
|
type GitHubURL struct {
|
|
url string
|
|
repository string
|
|
}
|
|
|
|
func (url GitHubURL) URL() string {
|
|
return url.url
|
|
}
|
|
|
|
func (url GitHubURL) Repository() string {
|
|
return url.repository
|
|
}
|
|
|
|
func (url GitHubURL) IsHTTPS() bool {
|
|
return strings.HasPrefix(url.url, "https://")
|
|
}
|
|
|
|
func (url GitHubURL) IsSSH() bool {
|
|
return strings.HasPrefix(url.url, "git@")
|
|
}
|
|
|
|
func (url GitHubURL) SSH() string {
|
|
return "git@github.com:" + url.repository
|
|
}
|
|
|
|
func (url GitHubURL) HTTPS() string {
|
|
return "https://github.com/" + url.repository
|
|
}
|
|
|
|
func (url GitHubURL) Directory() string {
|
|
return strings.TrimSuffix(filepath.Base(url.repository), filepath.Ext(url.repository))
|
|
}
|
|
|
|
func (url GitHubURL) BrowserURL() string {
|
|
return strings.TrimSuffix(url.HTTPS(), filepath.Ext(url.repository))
|
|
}
|
|
|
|
func (url GitHubURL) Matches(match string) bool {
|
|
repoName := strings.TrimSuffix(url.repository, filepath.Ext(url.repository))
|
|
return strings.Compare(strings.ToLower(repoName), strings.ToLower(match)) == 0
|
|
}
|
|
|
|
func (url GitHubURL) String() string {
|
|
return "github://" + url.repository
|
|
}
|