diff --git a/commands/apply.go b/commands/apply.go index 2e60c0319f5ce59f011e4f06ed4d7c1ec89da522..8e3305ace7011720ce5a0ebfa484588e173e9426 100644 --- a/commands/apply.go +++ b/commands/apply.go @@ -5,6 +5,8 @@ import ( "os" "path/filepath" "regexp" + + "github.com/github/hub/github" ) var cmdApply = &Command{ @@ -20,8 +22,22 @@ patch to the working copy. `, } +var cmdAm = &Command{ + Run: apply, + GitExtension: true, + Usage: "am GITHUB-URL", + Short: "Apply a patch to files and/or to the index", + Long: `Downloads the patch file for the pull request or commit at the URL and +applies that patch from disk with git am or git apply. Similar to +cherry-pick, but doesn't add new remotes. git am creates commits while +preserving authorship info while apply only applies the +patch to the working copy. +`, +} + func init() { CmdRunner.Use(cmdApply) + CmdRunner.Use(cmdAm) } /* @@ -44,44 +60,50 @@ func apply(command *Command, args *Args) { } func transformApplyArgs(args *Args) { - urlRegexp := regexp.MustCompile("^https?://(gist\\.)?github\\.com/") - for _, url := range args.Params { - if urlRegexp.MatchString(url) { - idx := args.IndexOfParam(url) - gist := urlRegexp.FindStringSubmatch(url)[1] == "gist." - - fragmentRegexp := regexp.MustCompile("#.+") - url = fragmentRegexp.ReplaceAllString(url, "") - pullRegexp := regexp.MustCompile("(/pull/\\d+)/\\w*$") - if !gist { - if pullRegexp.MatchString(url) { - pull := pullRegexp.FindStringSubmatch(url)[1] - url = pullRegexp.ReplaceAllString(url, pull) - } + urlRegexp := regexp.MustCompile("^https?://(gist\\.)github\\.com/") + for _, arg := range args.Params { + var ( + url string + gist bool + ) + projectURL, err := github.ParseURL(arg) + if err == nil { + pullRegexp := regexp.MustCompile("/(pull|commit)/([0-9a-f]+)") + match := pullRegexp.FindStringSubmatch(projectURL.Path) + if match != nil { + url = projectURL.Project.WebURL("", "", match[1]+"/"+match[2]) } - - var ext string + } else { + gist = urlRegexp.MatchString(arg) if gist { - ext = ".txt" - } else { - ext = ".patch" - } - - if filepath.Ext(url) != ext { - url += ext + url = arg } + } - var prefix string - if gist { - prefix = "gist-" - } + if url == "" { + continue + } - patchFile := filepath.Join(os.TempDir(), prefix+filepath.Base(url)) + var ext string + if gist { + ext = ".txt" + } else { + ext = ".patch" + } - args.Before("curl", "-#LA", fmt.Sprintf("gh %s", Version), url, "-o", patchFile) - args.Params[idx] = patchFile + idx := args.IndexOfParam(arg) + if filepath.Ext(url) != ext { + url += ext + } - break + var prefix string + if gist { + prefix = "gist-" } + + patchFile := filepath.Join(os.TempDir(), prefix+filepath.Base(url)) + + args.Before("curl", "-#LA", fmt.Sprintf("gh %s", Version), url, "-o", patchFile) + args.Params[idx] = patchFile } } diff --git a/features/support/fakebin/curl b/features/support/fakebin/curl new file mode 100755 index 0000000000000000000000000000000000000000..b12906f171233a60c590d5559a6818071a2d2dbe --- /dev/null +++ b/features/support/fakebin/curl @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +url="$3" +file="$5" + +if [ "${url%.patch}" = "$url" ]; then + echo "invalid pull request URL: $url" >&2 + exit 1 +fi + +cat > "$file" < +Date: Tue, 24 Jun 2014 11:07:05 -0700 +Subject: [PATCH] Create a README +--- +diff --git a/README.md b/README.md +new file mode 100644 +index 0000000..ce01362 +--- /dev/null ++++ b/README.md ++hello +-- +1.9.3 +OUT