提交 76b49068 编写于 作者: J Jingwen Owen Ou

Merge branch 'add_no_op'

......@@ -18,13 +18,17 @@ func (cmd Cmd) String() string {
}
func (cmd *Cmd) WithArg(arg string) *Cmd {
cmd.Args = append(cmd.Args, arg)
if arg != "" {
cmd.Args = append(cmd.Args, arg)
}
return cmd
}
func (cmd *Cmd) WithArgs(args ...string) *Cmd {
cmd.Args = append(cmd.Args, args...)
for _, arg := range args {
cmd.WithArg(arg)
}
return cmd
}
......@@ -64,9 +68,9 @@ func (cmd *Cmd) SysExec() error {
}
func New(name string) *Cmd {
return &Cmd{name, make([]string, 0)}
return &Cmd{Name: name, Args: make([]string, 0)}
}
func NewWithArray(cmd []string) *Cmd {
return &Cmd{cmd[0], cmd[1:]}
return &Cmd{Name: cmd[0], Args: cmd[1:]}
}
......@@ -6,10 +6,12 @@ import (
)
type Args struct {
Executable string
Command string
Params []string
beforeChain []*cmd.Cmd
afterChain []*cmd.Cmd
Noop bool
}
func (a *Args) Before(command ...string) {
......@@ -20,6 +22,12 @@ func (a *Args) After(command ...string) {
a.afterChain = append(a.afterChain, cmd.NewWithArray(command))
}
func (a *Args) Replace(executable, command string, params ...string) {
a.Executable = executable
a.Command = command
a.Params = params
}
func (a *Args) Commands() []*cmd.Cmd {
result := a.beforeChain
result = append(result, a.ToCmd())
......@@ -29,7 +37,7 @@ func (a *Args) Commands() []*cmd.Cmd {
}
func (a *Args) ToCmd() *cmd.Cmd {
return cmd.New("git").WithArg(a.Command).WithArgs(a.Params...)
return cmd.New(a.Executable).WithArg(a.Command).WithArgs(a.Params...)
}
func (a *Args) GetParam(i int) string {
......@@ -99,7 +107,7 @@ func NewArgs(args []string) *Args {
params = args[1:]
}
return &Args{command, params, make([]*cmd.Cmd, 0), make([]*cmd.Cmd, 0)}
return &Args{Executable: "git", Command: command, Params: params, beforeChain: make([]*cmd.Cmd, 0), afterChain: make([]*cmd.Cmd, 0)}
}
func removeItem(slice []string, index int) (newSlice []string, item string) {
......
......@@ -3,7 +3,6 @@ package commands
import (
"github.com/jingweno/gh/github"
"github.com/jingweno/gh/utils"
"os"
)
var cmdBrowse = &Command{
......@@ -25,10 +24,32 @@ func init() {
cmdBrowse.Flag.StringVar(&flagBrowseRepo, "r", "", "REPOSITORY")
}
/*
$ gh browse
> open https://github.com/YOUR_USER/CURRENT_REPO
$ gh browse commit/SHA
> open https://github.com/YOUR_USER/CURRENT_REPO/commit/SHA
$ gh browse issues
> open https://github.com/YOUR_USER/CURRENT_REPO/issues
$ gh browse -u jingweno -r gh
> open https://github.com/jingweno/gh
$ gh browse -u jingweno -r gh commit/SHA
> open https://github.com/jingweno/gh/commit/SHA
$ gh browse -r resque
> open https://github.com/YOUR_USER/resque
$ gh browse -r resque network
> open https://github.com/YOUR_USER/resque/network
*/
func browse(command *Command, args *Args) {
subpage := "tree"
if !args.IsParamsEmpty() {
subpage = args.FirstParam()
subpage = args.RemoveParam(0)
}
project := github.CurrentProject()
......@@ -38,8 +59,11 @@ func browse(command *Command, args *Args) {
}
url := project.WebURL(flagBrowseRepo, flagBrowseUser, subpage)
err := browserCommand(url)
utils.Check(err)
launcher, err := utils.BrowserLauncher()
if err != nil {
utils.Check(err)
}
os.Exit(0)
args.Replace(launcher[0], "", launcher[1:]...)
args.AppendParams(url)
}
......@@ -19,23 +19,53 @@ success (0), error (1), failure (1), pending (2), no status (3)
`,
}
/*
$ gh ci-status
> (prints CI state of HEAD and exits with appropriate code)
> One of: success (0), error (1), failure (1), pending (2), no status (3)
$ gh ci-status BRANCH
> (prints CI state of BRANCH and exits with appropriate code)
> One of: success (0), error (1), failure (1), pending (2), no status (3)
$ gh ci-status SHA
> (prints CI state of SHA and exits with appropriate code)
> One of: success (0), error (1), failure (1), pending (2), no status (3)
*/
func ciStatus(cmd *Command, args *Args) {
ref := "HEAD"
if !args.IsParamsEmpty() {
ref = args.FirstParam()
ref = args.RemoveParam(0)
}
ref, err := git.Ref(ref)
utils.Check(err)
args.Replace("", "")
if args.Noop {
fmt.Printf("Would request CI status for %s", ref)
} else {
state, targetURL, desc, exitCode, err := fetchCiStatus(ref)
utils.Check(err)
fmt.Println(state)
if targetURL != "" {
fmt.Println(targetURL)
}
if desc != "" {
fmt.Println(desc)
}
os.Exit(exitCode)
}
}
func fetchCiStatus(ref string) (state, targetURL, desc string, exitCode int, err error) {
gh := github.New()
status, err := gh.CiStatus(ref)
utils.Check(err)
if err != nil {
return
}
var state string
var targetURL string
var desc string
var exitCode int
if status == nil {
state = "no status"
} else {
......@@ -55,13 +85,5 @@ func ciStatus(cmd *Command, args *Args) {
exitCode = 3
}
fmt.Println(state)
if targetURL != "" {
fmt.Println(targetURL)
}
if desc != "" {
fmt.Println(desc)
}
os.Exit(exitCode)
return
}
......@@ -20,13 +20,13 @@ For repositories under your GitHub login, -p is implicit.
/**
$ gh clone jingweno/gh
> git clone git://github.com/jingweno/gh
> git clone git://github.com/jingweno/gh.git
$ gh clone -p jingweno/gh
> git clone git@github.com:jingweno/gh.git
$ gh clone jekyll_and_hype
> git clone git://github.com/YOUR_LOGIN/jekyll_and_hype.
$ gh clone jekyll_and_hyde
> git clone git://github.com/YOUR_LOGIN/jekyll_and_hyde.git
$ gh clone -p jekyll_and_hyde
> git clone git@github.com:YOUR_LOGIN/jekyll_and_hyde.git
......@@ -49,10 +49,10 @@ func transformCloneArgs(args *Args) {
if nameWithOwnerRegexp.MatchString(a) && !isDir(a) {
name, owner := parseCloneNameAndOwner(a)
config := github.CurrentConfig()
isSSH = isSSH || owner == config.User
if owner == "" {
owner = config.User
}
isSSH = isSSH || owner == config.User
project := github.Project{Name: name, Owner: owner}
url := project.GitURL(name, owner, isSSH)
......
......@@ -38,6 +38,12 @@ func TestTransformCloneArgs(t *testing.T) {
assert.Equal(t, 1, args.ParamsSize())
assert.Equal(t, "git@github.com:acl-services/devise-acl.git", args.FirstParam())
args = NewArgs([]string{"clone", "jekyll_and_hyde"})
transformCloneArgs(args)
assert.Equal(t, 1, args.ParamsSize())
assert.Equal(t, "git://github.com/jingweno/jekyll_and_hyde.git", args.FirstParam())
args = NewArgs([]string{"clone", "-p", "jekyll_and_hyde"})
transformCloneArgs(args)
......
......@@ -4,7 +4,6 @@ import (
"fmt"
"github.com/jingweno/gh/github"
"github.com/jingweno/gh/utils"
"os"
"regexp"
)
......@@ -26,6 +25,16 @@ func init() {
cmdCompare.Flag.StringVar(&flagCompareUser, "u", "", "USER")
}
/*
$ gh compare refactor
> open https://github.com/CURRENT_REPO/compare/refactor
$ gh compare 1.0..1.1
> open https://github.com/CURRENT_REPO/compare/1.0...1.1
$ gh compare -u other-user patch
> open https://github.com/other-user/REPO/compare/patch
*/
func compare(command *Command, args *Args) {
project := github.CurrentProject()
......@@ -40,10 +49,13 @@ func compare(command *Command, args *Args) {
r = transformToTripleDots(r)
subpage := utils.ConcatPaths("compare", r)
url := project.WebURL("", flagCompareUser, subpage)
err := browserCommand(url)
utils.Check(err)
launcher, err := utils.BrowserLauncher()
if err != nil {
utils.Check(err)
}
os.Exit(0)
args.Replace(launcher[0], "", launcher[1:]...)
args.AppendParams(url)
}
func transformToTripleDots(r string) string {
......
......@@ -4,7 +4,6 @@ import (
"fmt"
"github.com/jingweno/gh/github"
"github.com/jingweno/gh/utils"
"os"
)
var cmdFork = &Command{
......@@ -22,16 +21,32 @@ func init() {
cmdFork.Flag.BoolVar(&flagForkNoRemote, "no-remote", false, "")
}
/*
$ gh fork
[ repo forked on GitHub ]
> git remote add -f YOUR_USER git@github.com:YOUR_USER/CURRENT_REPO.git
$ gh fork --no-remote
[ repo forked on GitHub ]
*/
func fork(cmd *Command, args *Args) {
gh := github.New()
project := gh.Project
newRemote, err := gh.ForkRepository(project.Name, project.Owner, flagForkNoRemote)
utils.Check(err)
var forkURL string
if args.Noop {
args.Before(fmt.Sprintf("Would request a fork to %s:%s", project.Owner, project.Name), "")
forkURL = "FORK_URL"
} else {
repo, err := gh.ForkRepository(project.Name, project.Owner, flagForkNoRemote)
utils.Check(err)
if !flagForkNoRemote && newRemote != "" {
fmt.Printf("New remote: %s\n", newRemote)
forkURL = repo.SshURL
}
os.Exit(0)
if !flagForkNoRemote {
newRemote := gh.Config.User
args.Replace("git", "remote", "add", "-f", newRemote, forkURL)
args.After("echo", fmt.Sprintf("New remote: %s", newRemote))
}
}
......@@ -8,7 +8,6 @@ import (
"github.com/jingweno/gh/github"
"github.com/jingweno/gh/utils"
"io/ioutil"
"log"
"os"
"regexp"
"strings"
......@@ -43,52 +42,86 @@ func init() {
cmdPullRequest.Flag.StringVar(&flagPullRequestIssue, "i", "", "ISSUE")
}
/*
# while on a topic branch called "feature":
$ gh pull-request
[ opens text editor to edit title & body for the request ]
[ opened pull request on GitHub for "YOUR_USER:feature" ]
# explicit pull base & head:
$ gh pull-request -b jingweno:master -h jingweno:feature
$ gh pull-request -i 123
[ attached pull request to issue #123 ]
*/
func pullRequest(cmd *Command, args *Args) {
var title, body string
var (
title, body string
err error
)
if args.ParamsSize() == 1 {
title = args.FirstParam()
title = args.RemoveParam(0)
}
gh := github.New()
repo := gh.Project.LocalRepoWith(flagPullRequestBase, flagPullRequestHead)
if title == "" && flagPullRequestIssue == "" {
messageFile, err := git.PullReqMsgFile()
utils.Check(err)
title, body, err = writePullRequestTitleAndBody(repo)
}
err = writePullRequestChanges(repo, messageFile)
utils.Check(err)
if title == "" && flagPullRequestIssue == "" {
utils.Check(fmt.Errorf("Aborting due to empty pull request title"))
}
editorPath, err := git.EditorPath()
var pullRequestURL string
if args.Noop {
args.Before(fmt.Sprintf("Would request a pull request to %s from %s", repo.FullBase(), repo.FullHead()), "")
pullRequestURL = "PULL_REQUEST_URL"
} else {
if title != "" {
pullRequestURL, err = gh.CreatePullRequest(repo.Base, repo.Head, title, body)
}
utils.Check(err)
err = editTitleAndBody(editorPath, messageFile)
if flagPullRequestIssue != "" {
pullRequestURL, err = gh.CreatePullRequestForIssue(repo.Base, repo.Head, flagPullRequestIssue)
}
utils.Check(err)
title, body, err = readTitleAndBody(messageFile)
utils.Check(err)
}
err = os.Remove(messageFile)
utils.Check(err)
args.Replace("echo", "", pullRequestURL)
}
func writePullRequestTitleAndBody(repo *github.Repo) (title, body string, err error) {
messageFile, err := git.PullReqMsgFile()
if err != nil {
return
}
if title == "" && flagPullRequestIssue == "" {
log.Fatal("Aborting due to empty pull request title")
err = writePullRequestChanges(repo, messageFile)
if err != nil {
return
}
var pullRequestURL string
var err error
if title != "" {
pullRequestURL, err = gh.CreatePullRequest(repo.Base, repo.Head, title, body)
editorPath, err := git.EditorPath()
if err != nil {
return
}
if flagPullRequestIssue != "" {
pullRequestURL, err = gh.CreatePullRequestForIssue(repo.Base, repo.Head, flagPullRequestIssue)
err = editTitleAndBody(editorPath, messageFile)
if err != nil {
return
}
utils.Check(err)
title, body, err = readTitleAndBody(messageFile)
if err != nil {
return
}
fmt.Println(pullRequestURL)
err = os.Remove(messageFile)
os.Exit(0)
return
}
func writePullRequestChanges(repo *github.Repo, messageFile string) error {
......
......@@ -33,7 +33,7 @@ then uses your GitHub login.
> git remote add origin git://github.com/YOUR_LOGIN/THIS_REPO.git
*/
func remote(command *Command, args *Args) {
if args.ParamsSize() >= 2 && (args.Command == "add" || args.Command == "set-url") {
if args.ParamsSize() >= 2 && (args.FirstParam() == "add" || args.FirstParam() == "set-url") {
transformRemoteArgs(args)
}
}
......
......@@ -2,6 +2,7 @@ package commands
import (
"fmt"
"github.com/jingweno/gh/cmd"
"github.com/jingweno/gh/git"
)
......@@ -16,6 +17,7 @@ func (r *Runner) Execute() error {
}
expandAlias(args)
slurpGlobalFlags(args)
for _, cmd := range All() {
if cmd.Name() == args.Command && cmd.Runnable() {
......@@ -33,15 +35,10 @@ func (r *Runner) Execute() error {
cmd.Run(cmd, args)
cmds := args.Commands()
length := len(cmds)
for i, c := range cmds {
var err error
if i == (length - 1) {
err = c.SysExec()
} else {
err = c.Exec()
}
if args.Noop {
printCommands(cmds)
} else {
err := executeCommands(cmds)
if err != nil {
return err
}
......@@ -54,6 +51,39 @@ func (r *Runner) Execute() error {
return git.SysExec(args.Command, args.Params...)
}
func slurpGlobalFlags(args *Args) {
for i, p := range args.Params {
if p == "--no-op" {
args.Noop = true
args.RemoveParam(i)
}
}
}
func printCommands(cmds []*cmd.Cmd) {
for _, c := range cmds {
fmt.Println(c)
}
}
func executeCommands(cmds []*cmd.Cmd) error {
length := len(cmds)
for i, c := range cmds {
var err error
if i == (length - 1) {
err = c.SysExec()
} else {
err = c.Exec()
}
if err != nil {
return err
}
}
return nil
}
func expandAlias(args *Args) {
cmd := args.Command
expandedCmd, err := git.Config(fmt.Sprintf("alias.%s", cmd))
......
......@@ -2,25 +2,12 @@ package commands
import (
"fmt"
"github.com/jingweno/gh/cmd"
"github.com/jingweno/gh/github"
"github.com/jingweno/gh/utils"
"github.com/jingweno/octokat"
"os"
"regexp"
)
func browserCommand(url string) error {
launcher, err := utils.BrowserLauncher()
if err != nil {
return err
}
launcher = append(launcher, url)
c := cmd.NewWithArray(launcher)
return c.Exec()
}
func isDir(file string) bool {
f, err := os.Open(file)
if err != nil {
......
......@@ -3,7 +3,6 @@ package github
import (
"errors"
"fmt"
"github.com/jingweno/gh/git"
"github.com/jingweno/octokat"
)
......@@ -14,7 +13,7 @@ const (
type GitHub struct {
Project *Project
config *Config
Config *Config
}
func (gh *GitHub) PullRequest(id string) (*octokat.PullRequest, error) {
......@@ -59,10 +58,10 @@ func (gh *GitHub) CiStatus(sha string) (*octokat.Status, error) {
return &statuses[0], nil
}
func (gh *GitHub) ForkRepository(name, owner string, noRemote bool) (newRemote string, err error) {
func (gh *GitHub) ForkRepository(name, owner string, noRemote bool) (repo *octokat.Repository, err error) {
client := gh.client()
config := gh.config
repo, err := client.Repository(octokat.Repo{name, config.User})
config := gh.Config
repo, err = client.Repository(octokat.Repo{name, config.User})
if repo != nil && err == nil {
msg := fmt.Sprintf("Error creating fork: %s exists on %s", repo.FullName, GitHubHost)
err = errors.New(msg)
......@@ -70,14 +69,6 @@ func (gh *GitHub) ForkRepository(name, owner string, noRemote bool) (newRemote s
}
repo, err = client.Fork(octokat.Repo{name, owner}, nil)
if err != nil {
return
}
if !noRemote {
newRemote = config.User
err = git.Spawn("remote", "add", "-f", config.User, repo.SshURL)
}
return
}
......@@ -85,7 +76,7 @@ func (gh *GitHub) ForkRepository(name, owner string, noRemote bool) (newRemote s
func (gh *GitHub) ExpandRemoteUrl(owner, name string, isSSH bool) (url string) {
project := gh.Project
if owner == "origin" {
config := gh.config
config := gh.Config
owner = config.FetchUser()
}
......@@ -130,7 +121,7 @@ func findOrCreateToken(user, password string) (string, error) {
}
func (gh *GitHub) client() *octokat.Client {
config := gh.config
config := gh.Config
config.FetchCredentials()
return octokat.NewClient().WithToken(config.Token)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册