This commit is contained in:
Jingwen Owen Ou 2013-07-19 22:54:43 -07:00
Родитель 46b5cca729 2032d4c05a
Коммит 4f7494d744
10 изменённых файлов: 216 добавлений и 86 удалений

Просмотреть файл

@ -2,7 +2,6 @@ package commands
import (
"fmt"
"github.com/jingweno/gh/git"
"github.com/jingweno/gh/utils"
)
@ -43,13 +42,8 @@ func transformCheckoutArgs(args *Args) error {
user := pullRequest.User.Login
branch := pullRequest.Head.Ref
remoteExists, err := checkIfRemoteExists(user)
if err != nil {
return err
}
args.RemoveParam(0) // Remove the pull request URL
if remoteExists {
if hasGitRemote(user) {
updateExistingRemote(args, user, branch)
} else {
sshURL, err := convertToGitURL(pullRequest)
@ -74,21 +68,6 @@ func transformCheckoutArgs(args *Args) error {
return nil
}
func checkIfRemoteExists(remote string) (bool, error) {
remotes, err := git.Remotes()
if err != nil {
return false, err
}
for _, r := range remotes {
if r.Name == remote {
return true, nil
}
}
return false, nil
}
func updateExistingRemote(args *Args, user, branch string) {
args.Before("git", "remote", "set-branches", "--add", user, branch)
remoteURL := fmt.Sprintf("+refs/heads/%s:refs/remotes/%s/%s", branch, user, branch)

76
commands/cherry_pick.go Normal file
Просмотреть файл

@ -0,0 +1,76 @@
package commands
import (
"fmt"
"github.com/jingweno/gh/github"
"regexp"
)
var cmdCherryPick = &Command{
Run: cherryPick,
GitExtension: true,
Usage: "cherry-pick GITHUB-REF",
Short: "Apply the changes introduced by some existing commits",
Long: `Cherry-pick a commit from a fork using either full URL to the commit
or GitHub-flavored Markdown notation, which is user@sha. If the remote
doesn't yet exist, it will be added. A git-fetch(1) user is issued
prior to the cherry-pick attempt.
`,
}
/*
$ gh cherry-pick https://github.com/jingweno/gh/commit/a319d88#comments
> git remote add -f jingweno git://github.com/jingweno/gh.git
> git cherry-pick a319d88
$ gh cherry-pick jingweno@a319d88
> git remote add -f jingweno git://github.com/jingweno/gh.git
> git cherry-pick a319d88
$ gh cherry-pick jingweno@SHA
> git fetch jingweno
> git cherry-pick SHA
*/
func cherryPick(command *Command, args *Args) {
if args.IndexOfParam("-m") == -1 && args.IndexOfParam("--mainline") == -1 {
transformCherryPickArgs(args)
}
}
func transformCherryPickArgs(args *Args) {
ref := args.LastParam()
project, sha := parseCherryPickProjectAndSha(ref)
if project != nil {
args.ReplaceParam(args.IndexOfParam(ref), sha)
if hasGitRemote(project.Owner) {
args.Before("git", "fetch", project.Owner)
} else {
args.Before("git", "remote", "add", "-f", project.Owner, project.GitURL("", "", false))
}
}
}
func parseCherryPickProjectAndSha(ref string) (project *github.Project, sha string) {
url, err := github.ParseURL(ref)
if err == nil {
commitRegex := regexp.MustCompile("^commit\\/([a-f0-9]{7,40})")
projectPath := url.ProjectPath()
if commitRegex.MatchString(projectPath) {
sha = commitRegex.FindStringSubmatch(projectPath)[1]
project = &url.Project
return
}
}
ownerWithShaRegexp := regexp.MustCompile(fmt.Sprintf("^(%s)@([a-f0-9]{7,40})$"))
if ownerWithShaRegexp.MatchString(ref) {
matches := ownerWithShaRegexp.FindStringSubmatch(ref)
sha = matches[2]
project = github.CurrentProject()
project.Owner = matches[1]
}
return
}

Просмотреть файл

@ -0,0 +1,32 @@
package commands
import (
"github.com/bmizerany/assert"
"testing"
)
func TestParseCherryPickProjectAndSha(t *testing.T) {
ref := "https://github.com/jingweno/gh/commit/a319d88#comments"
project, sha := parseCherryPickProjectAndSha(ref)
assert.Equal(t, "jingweno", project.Owner)
assert.Equal(t, "gh", project.Name)
assert.Equal(t, "a319d88", sha)
ref = "https://github.com/jingweno/gh/commit/a319d88#comments"
project, sha = parseCherryPickProjectAndSha(ref)
assert.Equal(t, "jingweno", project.Owner)
assert.Equal(t, "gh", project.Name)
assert.Equal(t, "a319d88", sha)
}
func TestTransformCherryPickArgs(t *testing.T) {
args := NewArgs([]string{"cherry-pick", "https://github.com/jingweno/gh/commit/a319d88#comments"})
transformCherryPickArgs(args)
cmds := args.Commands()
assert.Equal(t, 2, len(cmds))
assert.Equal(t, "git remote add -f jingweno git://github.com/jingweno/gh.git", cmds[0].String())
assert.Equal(t, "git cherry-pick a319d88", cmds[1].String())
}

Просмотреть файл

@ -55,6 +55,7 @@ var Branching = []*Command{
cmdCheckout,
cmdMerge,
cmdApply,
cmdCherryPick,
}
var Remote = []*Command{

Просмотреть файл

@ -1,7 +1,6 @@
package commands
import (
"github.com/jingweno/gh/git"
"github.com/jingweno/gh/github"
"github.com/jingweno/gh/utils"
"regexp"
@ -41,17 +40,12 @@ func fetch(command *Command, args *Args) {
}
func tranformFetchArgs(args *Args) error {
remotes, err := git.Remotes()
if err != nil {
return err
}
names := parseRemoteNames(args)
gh := github.New()
projects := []github.Project{}
ownerRegexp := regexp.MustCompile(OwnerRe)
for _, name := range names {
if ownerRegexp.MatchString(name) && !isRemoteExist(remotes, name) {
if ownerRegexp.MatchString(name) && !hasGitRemote(name) {
project := github.NewProjectFromNameAndOwner("", name)
repo, err := gh.Repository(project)
if err != nil {
@ -95,13 +89,3 @@ func parseRemoteNames(args *Args) (names []string) {
return
}
func isRemoteExist(remotes []*git.GitRemote, name string) bool {
for _, r := range remotes {
if r.Name == name {
return true
}
}
return false
}

Просмотреть файл

@ -3,6 +3,8 @@ package commands
import (
"fmt"
"github.com/jingweno/gh/github"
"github.com/jingweno/gh/git"
"github.com/jingweno/gh/utils"
"github.com/jingweno/octokat"
"os"
"regexp"
@ -23,13 +25,19 @@ func isDir(file string) bool {
return fi.IsDir()
}
func parsePullRequestId(url string) string {
pullURLRegex := regexp.MustCompile("https://github\\.com/.+/.+/pull/(\\d+)")
if pullURLRegex.MatchString(url) {
return pullURLRegex.FindStringSubmatch(url)[1]
func parsePullRequestId(rawurl string) (id string) {
url, err := github.ParseURL(rawurl)
if err != nil {
return
}
return ""
pullURLRegex := regexp.MustCompile("^pull/(\\d+)")
projectPath := url.ProjectPath()
if pullURLRegex.MatchString(projectPath) {
id = pullURLRegex.FindStringSubmatch(projectPath)[1]
}
return
}
func fetchPullRequest(id string) (*octokat.PullRequest, error) {
@ -52,12 +60,12 @@ func convertToGitURL(pullRequest *octokat.PullRequest) (string, error) {
user := pullRequest.User.Login
isSSH := pullRequest.Head.Repo.Private
project, err := github.ParseProjectFromURL(pullRequestURL)
url, err := github.ParseURL(pullRequestURL)
if err != nil {
return "", err
}
return project.GitURL("", user, isSSH), nil
return url.GitURL("", user, isSSH), nil
}
func parseRepoNameOwner(nameWithOwner string) (owner, name string, match bool) {
@ -80,3 +88,15 @@ func parseRepoNameOwner(nameWithOwner string) (owner, name string, match bool) {
return
}
func hasGitRemote(name string) bool {
remotes, err := git.Remotes()
utils.Check(err)
for _, remote := range remotes {
if remote.Name == name {
return true
}
}
return false
}

Просмотреть файл

@ -78,22 +78,17 @@ func CurrentProject() *Project {
return &Project{name, owner}
}
func ParseProjectFromURL(uu string) (*Project, error) {
u, err := url.Parse(uu)
if err != nil {
return nil, err
func NewProjectFromURL(url *url.URL) (*Project, error) {
if url.Host != GitHubHost || url.Scheme != "https" {
return nil, fmt.Errorf("Invalid GitHub URL: %s", url)
}
if u.Host != GitHubHost || u.Scheme != "https" {
return nil, fmt.Errorf("Invalid GitHub URL: %s", u)
parts := strings.SplitN(url.Path, "/", 4)
if len(parts) < 2 {
return nil, fmt.Errorf("Invalid GitHub URL: %s", url)
}
parts := strings.SplitN(u.Path, "/", 4)
if len(parts) >= 2 {
return &Project{Name: parts[2], Owner: parts[1]}, nil
}
return nil, fmt.Errorf("Invalid GitHub URL: %s", u)
return &Project{Name: parts[2], Owner: parts[1]}, nil
}
func NewProjectFromNameAndOwner(name, owner string) Project {

Просмотреть файл

@ -84,31 +84,3 @@ func TestMustMatchGitHubURL(t *testing.T) {
assert.Equal(t, "jingweno", url[1])
assert.Equal(t, "gh", url[2])
}
func TestParseProjectFromURL(t *testing.T) {
project, err :=
ParseProjectFromURL("https://github.com/jingweno/gh/pulls/21")
assert.Equal(t, nil, err)
assert.Equal(t, "jingweno", project.Owner)
assert.Equal(t, "gh", project.Name)
project, err =
ParseProjectFromURL("https://github.com/jingweno/gh")
assert.Equal(t, nil, err)
assert.Equal(t, "jingweno", project.Owner)
assert.Equal(t, "gh", project.Name)
project, err =
ParseProjectFromURL("https://github.com/jingweno/gh/")
assert.Equal(t, nil, err)
assert.Equal(t, "jingweno", project.Owner)
assert.Equal(t, "gh", project.Name)
project, err =
ParseProjectFromURL("http://github.com/jingweno/gh/")
assert.NotEqual(t, nil, err)
project, err =
ParseProjectFromURL("http://github.com/jingweno/")
assert.NotEqual(t, nil, err)
}

34
github/url.go Normal file
Просмотреть файл

@ -0,0 +1,34 @@
package github
import (
"net/url"
"strings"
)
type URL struct {
url.URL
Project
}
func (url URL) ProjectPath() (projectPath string) {
split := strings.SplitN(url.Path, "/", 4)
if len(split) > 3 {
projectPath = split[3]
}
return
}
func ParseURL(rawurl string) (*URL, error) {
url, err := url.Parse(rawurl)
if err != nil {
return nil, err
}
project, err := NewProjectFromURL(url)
if err != nil {
return nil, err
}
return &URL{Project: *project, URL: *url}, nil
}

37
github/url_test.go Normal file
Просмотреть файл

@ -0,0 +1,37 @@
package github
import (
"github.com/bmizerany/assert"
"testing"
)
func TestParseURL(t *testing.T) {
url, err :=
ParseURL("https://github.com/jingweno/gh/pulls/21")
assert.Equal(t, nil, err)
assert.Equal(t, "jingweno", url.Owner)
assert.Equal(t, "gh", url.Name)
assert.Equal(t, "pulls/21", url.ProjectPath())
url, err =
ParseURL("https://github.com/jingweno/gh")
assert.Equal(t, nil, err)
assert.Equal(t, "jingweno", url.Owner)
assert.Equal(t, "gh", url.Name)
assert.Equal(t, "", url.ProjectPath())
url, err =
ParseURL("https://github.com/jingweno/gh/")
assert.Equal(t, nil, err)
assert.Equal(t, "jingweno", url.Owner)
assert.Equal(t, "gh", url.Name)
assert.Equal(t, "", url.ProjectPath())
url, err =
ParseURL("http://github.com/jingweno/gh/")
assert.NotEqual(t, nil, err)
url, err =
ParseURL("http://github.com/jingweno/")
assert.NotEqual(t, nil, err)
}