Merge remote-tracking branch 'origin/master' into pr-count
This commit is contained in:
commit
1ba577ca36
18 changed files with 1123 additions and 84 deletions
|
|
@ -70,10 +70,6 @@ func prStatus(cmd *cobra.Command, args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
currentPRNumber, currentPRHeadRef, err := prSelectorForCurrentBranch(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentUser, err := ctx.AuthLogin()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -84,6 +80,11 @@ func prStatus(cmd *cobra.Command, args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
currentPRNumber, currentPRHeadRef, err := prSelectorForCurrentBranch(ctx, baseRepo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prPayload, err := api.PullRequests(apiClient, baseRepo, currentPRNumber, currentPRHeadRef, currentUser)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -263,7 +264,7 @@ func prView(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
openURL = pr.URL
|
||||
} else {
|
||||
prNumber, branchWithOwner, err := prSelectorForCurrentBranch(ctx)
|
||||
prNumber, branchWithOwner, err := prSelectorForCurrentBranch(ctx, baseRepo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -333,11 +334,7 @@ func prFromArg(apiClient *api.Client, baseRepo ghrepo.Interface, arg string) (*a
|
|||
return api.PullRequestForBranch(apiClient, baseRepo, arg)
|
||||
}
|
||||
|
||||
func prSelectorForCurrentBranch(ctx context.Context) (prNumber int, prHeadRef string, err error) {
|
||||
baseRepo, err := ctx.BaseRepo()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
func prSelectorForCurrentBranch(ctx context.Context, baseRepo ghrepo.Interface) (prNumber int, prHeadRef string, err error) {
|
||||
prHeadRef, err = ctx.Branch()
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -98,6 +98,36 @@ func TestPRStatus(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPRStatus_fork(t *testing.T) {
|
||||
initBlankContext("OWNER/REPO", "blueberries")
|
||||
http := initFakeHTTP()
|
||||
http.StubForkedRepoResponse("OWNER/REPO", "PARENT/REPO")
|
||||
|
||||
jsonFile, _ := os.Open("../test/fixtures/prStatusFork.json")
|
||||
defer jsonFile.Close()
|
||||
http.StubResponse(200, jsonFile)
|
||||
|
||||
defer utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
switch strings.Join(cmd.Args, " ") {
|
||||
case `git config --get-regexp ^branch\.blueberries\.(remote|merge)$`:
|
||||
return &outputStub{[]byte(`branch.blueberries.remote origin
|
||||
branch.blueberries.merge refs/heads/blueberries`)}
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
})()
|
||||
|
||||
output, err := RunCommand(prStatusCmd, "pr status")
|
||||
if err != nil {
|
||||
t.Fatalf("error running command `pr status`: %v", err)
|
||||
}
|
||||
|
||||
branchRE := regexp.MustCompile(`#10.*\[OWNER:blueberries\]`)
|
||||
if !branchRE.MatchString(output.String()) {
|
||||
t.Errorf("did not match current branch:\n%v", output.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPRStatus_reviewsAndChecks(t *testing.T) {
|
||||
initBlankContext("OWNER/REPO", "blueberries")
|
||||
http := initFakeHTTP()
|
||||
|
|
|
|||
327
command/repo.go
327
command/repo.go
|
|
@ -2,9 +2,14 @@ package command
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/cli/cli/api"
|
||||
"github.com/cli/cli/git"
|
||||
"github.com/cli/cli/internal/ghrepo"
|
||||
"github.com/cli/cli/utils"
|
||||
|
|
@ -14,12 +19,27 @@ import (
|
|||
func init() {
|
||||
RootCmd.AddCommand(repoCmd)
|
||||
repoCmd.AddCommand(repoCloneCmd)
|
||||
|
||||
repoCmd.AddCommand(repoCreateCmd)
|
||||
repoCreateCmd.Flags().StringP("description", "d", "", "Description of repository")
|
||||
repoCreateCmd.Flags().StringP("homepage", "h", "", "Repository home page URL")
|
||||
repoCreateCmd.Flags().StringP("team", "t", "", "The name of the organization team to be granted access")
|
||||
repoCreateCmd.Flags().Bool("enable-issues", true, "Enable issues in the new repository")
|
||||
repoCreateCmd.Flags().Bool("enable-wiki", true, "Enable wiki in the new repository")
|
||||
repoCreateCmd.Flags().Bool("public", false, "Make the new repository public")
|
||||
|
||||
repoCmd.AddCommand(repoForkCmd)
|
||||
repoForkCmd.Flags().String("clone", "prompt", "Clone fork: {true|false|prompt}")
|
||||
repoForkCmd.Flags().String("remote", "prompt", "Add remote for fork: {true|false|prompt}")
|
||||
repoForkCmd.Flags().Lookup("clone").NoOptDefVal = "true"
|
||||
repoForkCmd.Flags().Lookup("remote").NoOptDefVal = "true"
|
||||
|
||||
repoCmd.AddCommand(repoViewCmd)
|
||||
}
|
||||
|
||||
var repoCmd = &cobra.Command{
|
||||
Use: "repo",
|
||||
Short: "View repositories",
|
||||
Short: "Create, clone, fork, and view repositories",
|
||||
Long: `Work with GitHub repositories.
|
||||
|
||||
A repository can be supplied as an argument in any of the following formats:
|
||||
|
|
@ -37,8 +57,26 @@ To pass 'git clone' options, separate them with '--'.`,
|
|||
RunE: repoClone,
|
||||
}
|
||||
|
||||
var repoCreateCmd = &cobra.Command{
|
||||
Use: "create [<name>]",
|
||||
Short: "Create a new repository",
|
||||
Long: `Create a new GitHub repository.
|
||||
|
||||
Use the "ORG/NAME" syntax to create a repository within your organization.`,
|
||||
RunE: repoCreate,
|
||||
}
|
||||
|
||||
var repoForkCmd = &cobra.Command{
|
||||
Use: "fork [<repository>]",
|
||||
Short: "Create a fork of a repository",
|
||||
Long: `Create a fork of a repository.
|
||||
|
||||
With no argument, creates a fork of the current repository. Otherwise, forks the specified repository.`,
|
||||
RunE: repoFork,
|
||||
}
|
||||
|
||||
var repoViewCmd = &cobra.Command{
|
||||
Use: "view [<repo>]",
|
||||
Use: "view [<repository>]",
|
||||
Short: "View a repository in the browser",
|
||||
Long: `View a GitHub repository in the browser.
|
||||
|
||||
|
|
@ -63,6 +101,289 @@ func repoClone(cmd *cobra.Command, args []string) error {
|
|||
return utils.PrepareCmd(cloneCmd).Run()
|
||||
}
|
||||
|
||||
func repoCreate(cmd *cobra.Command, args []string) error {
|
||||
projectDir, projectDirErr := git.ToplevelDir()
|
||||
|
||||
orgName := ""
|
||||
teamSlug, err := cmd.Flags().GetString("team")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var name string
|
||||
if len(args) > 0 {
|
||||
name = args[0]
|
||||
if strings.Contains(name, "/") {
|
||||
newRepo := ghrepo.FromFullName(name)
|
||||
orgName = newRepo.RepoOwner()
|
||||
name = newRepo.RepoName()
|
||||
}
|
||||
} else {
|
||||
if projectDirErr != nil {
|
||||
return projectDirErr
|
||||
}
|
||||
name = path.Base(projectDir)
|
||||
}
|
||||
|
||||
isPublic, err := cmd.Flags().GetBool("public")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hasIssuesEnabled, err := cmd.Flags().GetBool("enable-issues")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hasWikiEnabled, err := cmd.Flags().GetBool("enable-wiki")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
description, err := cmd.Flags().GetString("description")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
homepage, err := cmd.Flags().GetString("homepage")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: move this into constant within `api`
|
||||
visibility := "PRIVATE"
|
||||
if isPublic {
|
||||
visibility = "PUBLIC"
|
||||
}
|
||||
|
||||
input := api.RepoCreateInput{
|
||||
Name: name,
|
||||
Visibility: visibility,
|
||||
OwnerID: orgName,
|
||||
TeamID: teamSlug,
|
||||
Description: description,
|
||||
Homepage: homepage,
|
||||
HasIssuesEnabled: hasIssuesEnabled,
|
||||
HasWikiEnabled: hasWikiEnabled,
|
||||
}
|
||||
|
||||
ctx := contextForCommand(cmd)
|
||||
client, err := apiClientForContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repo, err := api.RepoCreate(client, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out := cmd.OutOrStdout()
|
||||
greenCheck := utils.Green("✓")
|
||||
isTTY := false
|
||||
if outFile, isFile := out.(*os.File); isFile {
|
||||
isTTY = utils.IsTerminal(outFile)
|
||||
if isTTY {
|
||||
// FIXME: duplicates colorableOut
|
||||
out = utils.NewColorable(outFile)
|
||||
}
|
||||
}
|
||||
|
||||
if isTTY {
|
||||
fmt.Fprintf(out, "%s Created repository %s on GitHub\n", greenCheck, ghrepo.FullName(repo))
|
||||
} else {
|
||||
fmt.Fprintln(out, repo.URL)
|
||||
}
|
||||
|
||||
remoteURL := repo.URL + ".git"
|
||||
|
||||
if projectDirErr == nil {
|
||||
// TODO: use git.AddRemote
|
||||
remoteAdd := git.GitCommand("remote", "add", "origin", remoteURL)
|
||||
remoteAdd.Stdout = os.Stdout
|
||||
remoteAdd.Stderr = os.Stderr
|
||||
err = utils.PrepareCmd(remoteAdd).Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isTTY {
|
||||
fmt.Fprintf(out, "%s Added remote %s\n", greenCheck, remoteURL)
|
||||
}
|
||||
} else if isTTY {
|
||||
doSetup := false
|
||||
err := Confirm(fmt.Sprintf("Create a local project directory for %s?", ghrepo.FullName(repo)), &doSetup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if doSetup {
|
||||
path := repo.Name
|
||||
|
||||
gitInit := git.GitCommand("init", path)
|
||||
gitInit.Stdout = os.Stdout
|
||||
gitInit.Stderr = os.Stderr
|
||||
err = utils.PrepareCmd(gitInit).Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gitRemoteAdd := git.GitCommand("-C", path, "remote", "add", "origin", remoteURL)
|
||||
gitRemoteAdd.Stdout = os.Stdout
|
||||
gitRemoteAdd.Stderr = os.Stderr
|
||||
err = utils.PrepareCmd(gitRemoteAdd).Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(out, "%s Initialized repository in './%s/'\n", greenCheck, path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isURL(arg string) bool {
|
||||
return strings.HasPrefix(arg, "http:/") || strings.HasPrefix(arg, "https:/")
|
||||
}
|
||||
|
||||
var Since = func(t time.Time) time.Duration {
|
||||
return time.Since(t)
|
||||
}
|
||||
|
||||
func repoFork(cmd *cobra.Command, args []string) error {
|
||||
ctx := contextForCommand(cmd)
|
||||
|
||||
clonePref, err := cmd.Flags().GetString("clone")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remotePref, err := cmd.Flags().GetString("remote")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apiClient, err := apiClientForContext(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create client: %w", err)
|
||||
}
|
||||
|
||||
var toFork ghrepo.Interface
|
||||
inParent := false // whether or not we're forking the repo we're currently "in"
|
||||
if len(args) == 0 {
|
||||
baseRepo, err := determineBaseRepo(cmd, ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to determine base repository: %w", err)
|
||||
}
|
||||
inParent = true
|
||||
toFork = baseRepo
|
||||
} else {
|
||||
repoArg := args[0]
|
||||
|
||||
if isURL(repoArg) {
|
||||
parsedURL, err := url.Parse(repoArg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("did not understand argument: %w", err)
|
||||
}
|
||||
|
||||
toFork, err = ghrepo.FromURL(parsedURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("did not understand argument: %w", err)
|
||||
}
|
||||
|
||||
} else {
|
||||
toFork = ghrepo.FromFullName(repoArg)
|
||||
if toFork.RepoName() == "" || toFork.RepoOwner() == "" {
|
||||
return fmt.Errorf("could not parse owner or repo name from %s", repoArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
greenCheck := utils.Green("✓")
|
||||
out := colorableOut(cmd)
|
||||
s := utils.Spinner()
|
||||
loading := utils.Gray("Forking ") + utils.Bold(utils.Gray(ghrepo.FullName(toFork))) + utils.Gray("...")
|
||||
s.Suffix = " " + loading
|
||||
s.FinalMSG = utils.Gray(fmt.Sprintf("- %s\n", loading))
|
||||
s.Start()
|
||||
|
||||
authLogin, err := ctx.AuthLogin()
|
||||
if err != nil {
|
||||
s.Stop()
|
||||
return fmt.Errorf("could not determine current username: %w", err)
|
||||
}
|
||||
|
||||
possibleFork := ghrepo.New(authLogin, toFork.RepoName())
|
||||
|
||||
forkedRepo, err := api.ForkRepo(apiClient, toFork)
|
||||
if err != nil {
|
||||
s.Stop()
|
||||
return fmt.Errorf("failed to fork: %w", err)
|
||||
}
|
||||
|
||||
s.Stop()
|
||||
// This is weird. There is not an efficient way to determine via the GitHub API whether or not a
|
||||
// given user has forked a given repo. We noticed, also, that the create fork API endpoint just
|
||||
// returns the fork repo data even if it already exists -- with no change in status code or
|
||||
// anything. We thus check the created time to see if the repo is brand new or not; if it's not,
|
||||
// we assume the fork already existed and report an error.
|
||||
created_ago := Since(forkedRepo.CreatedAt)
|
||||
if created_ago > time.Minute {
|
||||
fmt.Fprintf(out, "%s %s %s\n",
|
||||
utils.Yellow("!"),
|
||||
utils.Bold(ghrepo.FullName(possibleFork)),
|
||||
"already exists")
|
||||
} else {
|
||||
fmt.Fprintf(out, "%s Created fork %s\n", greenCheck, utils.Bold(ghrepo.FullName(forkedRepo)))
|
||||
}
|
||||
|
||||
if (inParent && remotePref == "false") || (!inParent && clonePref == "false") {
|
||||
return nil
|
||||
}
|
||||
|
||||
if inParent {
|
||||
remoteDesired := remotePref == "true"
|
||||
if remotePref == "prompt" {
|
||||
err = Confirm("Would you like to add a remote for the fork?", &remoteDesired)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prompt: %w", err)
|
||||
}
|
||||
}
|
||||
if remoteDesired {
|
||||
_, err := git.AddRemote("fork", forkedRepo.CloneURL, "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add remote: %w", err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(out, "%s Remote added at %s\n", greenCheck, utils.Bold("fork"))
|
||||
}
|
||||
} else {
|
||||
cloneDesired := clonePref == "true"
|
||||
if clonePref == "prompt" {
|
||||
err = Confirm("Would you like to clone the fork?", &cloneDesired)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prompt: %w", err)
|
||||
}
|
||||
}
|
||||
if cloneDesired {
|
||||
cloneCmd := git.GitCommand("clone", forkedRepo.CloneURL)
|
||||
cloneCmd.Stdin = os.Stdin
|
||||
cloneCmd.Stdout = os.Stdout
|
||||
cloneCmd.Stderr = os.Stderr
|
||||
err = utils.PrepareCmd(cloneCmd).Run()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clone fork: %w", err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(out, "%s Cloned fork\n", greenCheck)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var Confirm = func(prompt string, result *bool) error {
|
||||
p := &survey.Confirm{
|
||||
Message: prompt,
|
||||
Default: true,
|
||||
}
|
||||
return survey.AskOne(p, result)
|
||||
}
|
||||
|
||||
func repoView(cmd *cobra.Command, args []string) error {
|
||||
ctx := contextForCommand(cmd)
|
||||
|
||||
|
|
@ -75,7 +396,7 @@ func repoView(cmd *cobra.Command, args []string) error {
|
|||
openURL = fmt.Sprintf("https://github.com/%s", ghrepo.FullName(baseRepo))
|
||||
} else {
|
||||
repoArg := args[0]
|
||||
if strings.HasPrefix(repoArg, "http:/") || strings.HasPrefix(repoArg, "https:/") {
|
||||
if isURL(repoArg) {
|
||||
openURL = repoArg
|
||||
} else {
|
||||
openURL = fmt.Sprintf("https://github.com/%s", repoArg)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,342 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cli/cli/context"
|
||||
"github.com/cli/cli/utils"
|
||||
)
|
||||
|
||||
func TestRepoFork_already_forked(t *testing.T) {
|
||||
initContext = func() context.Context {
|
||||
ctx := context.NewBlank()
|
||||
ctx.SetBaseRepo("REPO")
|
||||
ctx.SetBranch("master")
|
||||
ctx.SetAuthLogin("someone")
|
||||
ctx.SetRemotes(map[string]string{
|
||||
"origin": "OWNER/REPO",
|
||||
})
|
||||
return ctx
|
||||
}
|
||||
http := initFakeHTTP()
|
||||
http.StubRepoResponse("OWNER", "REPO")
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, "repo fork --remote=false")
|
||||
if err != nil {
|
||||
t.Errorf("got unexpected error: %v", err)
|
||||
}
|
||||
r := regexp.MustCompile(`someone/REPO already exists`)
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func stubSince(d time.Duration) func() {
|
||||
originalSince := Since
|
||||
Since = func(t time.Time) time.Duration {
|
||||
return d
|
||||
}
|
||||
return func() {
|
||||
Since = originalSince
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoFork_in_parent(t *testing.T) {
|
||||
initBlankContext("OWNER/REPO", "master")
|
||||
defer stubSince(2 * time.Second)()
|
||||
http := initFakeHTTP()
|
||||
http.StubRepoResponse("OWNER", "REPO")
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, "repo fork --remote=false")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo fork`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
r := regexp.MustCompile(`Created fork someone/REPO`)
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoFork_outside(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
}{
|
||||
{
|
||||
name: "url arg",
|
||||
args: "repo fork --clone=false http://github.com/OWNER/REPO.git",
|
||||
},
|
||||
{
|
||||
name: "full name arg",
|
||||
args: "repo fork --clone=false OWNER/REPO",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer stubSince(2 * time.Second)()
|
||||
http := initFakeHTTP()
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, tt.args)
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo fork`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
r := regexp.MustCompile(`Created fork someone/REPO`)
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoFork_in_parent_yes(t *testing.T) {
|
||||
initBlankContext("OWNER/REPO", "master")
|
||||
defer stubSince(2 * time.Second)()
|
||||
http := initFakeHTTP()
|
||||
http.StubRepoResponse("OWNER", "REPO")
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
var seenCmds []*exec.Cmd
|
||||
defer utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
seenCmds = append(seenCmds, cmd)
|
||||
return &outputStub{}
|
||||
})()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, "repo fork --remote")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo fork`: %v", err)
|
||||
}
|
||||
|
||||
expectedCmds := []string{
|
||||
"git remote add -f fork https://github.com/someone/repo.git",
|
||||
"git fetch fork",
|
||||
}
|
||||
|
||||
for x, cmd := range seenCmds {
|
||||
eq(t, strings.Join(cmd.Args, " "), expectedCmds[x])
|
||||
}
|
||||
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
expectedLines := []*regexp.Regexp{
|
||||
regexp.MustCompile(`Created fork someone/REPO`),
|
||||
regexp.MustCompile(`Remote added at fork`),
|
||||
}
|
||||
for _, r := range expectedLines {
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoFork_outside_yes(t *testing.T) {
|
||||
defer stubSince(2 * time.Second)()
|
||||
http := initFakeHTTP()
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
var seenCmd *exec.Cmd
|
||||
defer utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
seenCmd = cmd
|
||||
return &outputStub{}
|
||||
})()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, "repo fork --clone OWNER/REPO")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo fork`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
eq(t, strings.Join(seenCmd.Args, " "), "git clone https://github.com/someone/repo.git")
|
||||
|
||||
expectedLines := []*regexp.Regexp{
|
||||
regexp.MustCompile(`Created fork someone/REPO`),
|
||||
regexp.MustCompile(`Cloned fork`),
|
||||
}
|
||||
for _, r := range expectedLines {
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoFork_outside_survey_yes(t *testing.T) {
|
||||
defer stubSince(2 * time.Second)()
|
||||
http := initFakeHTTP()
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
var seenCmd *exec.Cmd
|
||||
defer utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
seenCmd = cmd
|
||||
return &outputStub{}
|
||||
})()
|
||||
|
||||
oldConfirm := Confirm
|
||||
Confirm = func(_ string, result *bool) error {
|
||||
*result = true
|
||||
return nil
|
||||
}
|
||||
defer func() { Confirm = oldConfirm }()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, "repo fork OWNER/REPO")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo fork`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
eq(t, strings.Join(seenCmd.Args, " "), "git clone https://github.com/someone/repo.git")
|
||||
|
||||
expectedLines := []*regexp.Regexp{
|
||||
regexp.MustCompile(`Created fork someone/REPO`),
|
||||
regexp.MustCompile(`Cloned fork`),
|
||||
}
|
||||
for _, r := range expectedLines {
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoFork_outside_survey_no(t *testing.T) {
|
||||
defer stubSince(2 * time.Second)()
|
||||
http := initFakeHTTP()
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
cmdRun := false
|
||||
defer utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
cmdRun = true
|
||||
return &outputStub{}
|
||||
})()
|
||||
|
||||
oldConfirm := Confirm
|
||||
Confirm = func(_ string, result *bool) error {
|
||||
*result = false
|
||||
return nil
|
||||
}
|
||||
defer func() { Confirm = oldConfirm }()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, "repo fork OWNER/REPO")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo fork`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
eq(t, cmdRun, false)
|
||||
|
||||
r := regexp.MustCompile(`Created fork someone/REPO`)
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoFork_in_parent_survey_yes(t *testing.T) {
|
||||
initBlankContext("OWNER/REPO", "master")
|
||||
defer stubSince(2 * time.Second)()
|
||||
http := initFakeHTTP()
|
||||
http.StubRepoResponse("OWNER", "REPO")
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
var seenCmds []*exec.Cmd
|
||||
defer utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
seenCmds = append(seenCmds, cmd)
|
||||
return &outputStub{}
|
||||
})()
|
||||
|
||||
oldConfirm := Confirm
|
||||
Confirm = func(_ string, result *bool) error {
|
||||
*result = true
|
||||
return nil
|
||||
}
|
||||
defer func() { Confirm = oldConfirm }()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, "repo fork")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo fork`: %v", err)
|
||||
}
|
||||
|
||||
expectedCmds := []string{
|
||||
"git remote add -f fork https://github.com/someone/repo.git",
|
||||
"git fetch fork",
|
||||
}
|
||||
|
||||
for x, cmd := range seenCmds {
|
||||
eq(t, strings.Join(cmd.Args, " "), expectedCmds[x])
|
||||
}
|
||||
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
expectedLines := []*regexp.Regexp{
|
||||
regexp.MustCompile(`Created fork someone/REPO`),
|
||||
regexp.MustCompile(`Remote added at fork`),
|
||||
}
|
||||
for _, r := range expectedLines {
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoFork_in_parent_survey_no(t *testing.T) {
|
||||
initBlankContext("OWNER/REPO", "master")
|
||||
defer stubSince(2 * time.Second)()
|
||||
http := initFakeHTTP()
|
||||
http.StubRepoResponse("OWNER", "REPO")
|
||||
defer http.StubWithFixture(200, "forkResult.json")()
|
||||
|
||||
cmdRun := false
|
||||
defer utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
cmdRun = true
|
||||
return &outputStub{}
|
||||
})()
|
||||
|
||||
oldConfirm := Confirm
|
||||
Confirm = func(_ string, result *bool) error {
|
||||
*result = false
|
||||
return nil
|
||||
}
|
||||
defer func() { Confirm = oldConfirm }()
|
||||
|
||||
output, err := RunCommand(repoForkCmd, "repo fork")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo fork`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
eq(t, cmdRun, false)
|
||||
|
||||
r := regexp.MustCompile(`Created fork someone/REPO`)
|
||||
if !r.MatchString(output.String()) {
|
||||
t.Errorf("output did not match regexp /%s/\n> output\n%s\n", r, output)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoClone(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
@ -45,7 +373,7 @@ func TestRepoClone(t *testing.T) {
|
|||
})
|
||||
defer restoreCmd()
|
||||
|
||||
output, err := RunCommand(repoViewCmd, tt.args)
|
||||
output, err := RunCommand(repoCloneCmd, tt.args)
|
||||
if err != nil {
|
||||
t.Fatalf("error running command `repo clone`: %v", err)
|
||||
}
|
||||
|
|
@ -61,6 +389,196 @@ func TestRepoClone(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRepoCreate(t *testing.T) {
|
||||
ctx := context.NewBlank()
|
||||
ctx.SetBranch("master")
|
||||
initContext = func() context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
http := initFakeHTTP()
|
||||
http.StubResponse(200, bytes.NewBufferString(`
|
||||
{ "data": { "createRepository": {
|
||||
"repository": {
|
||||
"id": "REPOID",
|
||||
"url": "https://github.com/OWNER/REPO"
|
||||
}
|
||||
} } }
|
||||
`))
|
||||
|
||||
var seenCmd *exec.Cmd
|
||||
restoreCmd := utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
seenCmd = cmd
|
||||
return &outputStub{}
|
||||
})
|
||||
defer restoreCmd()
|
||||
|
||||
output, err := RunCommand(repoCreateCmd, "repo create REPO")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo create`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.String(), "https://github.com/OWNER/REPO\n")
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
if seenCmd == nil {
|
||||
t.Fatal("expected a command to run")
|
||||
}
|
||||
eq(t, strings.Join(seenCmd.Args, " "), "git remote add origin https://github.com/OWNER/REPO.git")
|
||||
|
||||
var reqBody struct {
|
||||
Query string
|
||||
Variables struct {
|
||||
Input map[string]interface{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(http.Requests) != 1 {
|
||||
t.Fatalf("expected 1 HTTP request, got %d", len(http.Requests))
|
||||
}
|
||||
|
||||
bodyBytes, _ := ioutil.ReadAll(http.Requests[0].Body)
|
||||
json.Unmarshal(bodyBytes, &reqBody)
|
||||
if repoName := reqBody.Variables.Input["name"].(string); repoName != "REPO" {
|
||||
t.Errorf("expected %q, got %q", "REPO", repoName)
|
||||
}
|
||||
if repoVisibility := reqBody.Variables.Input["visibility"].(string); repoVisibility != "PRIVATE" {
|
||||
t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
|
||||
}
|
||||
if _, ownerSet := reqBody.Variables.Input["ownerId"]; ownerSet {
|
||||
t.Error("expected ownerId not to be set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoCreate_org(t *testing.T) {
|
||||
ctx := context.NewBlank()
|
||||
ctx.SetBranch("master")
|
||||
initContext = func() context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
http := initFakeHTTP()
|
||||
http.StubResponse(200, bytes.NewBufferString(`
|
||||
{ "node_id": "ORGID"
|
||||
}
|
||||
`))
|
||||
http.StubResponse(200, bytes.NewBufferString(`
|
||||
{ "data": { "createRepository": {
|
||||
"repository": {
|
||||
"id": "REPOID",
|
||||
"url": "https://github.com/ORG/REPO"
|
||||
}
|
||||
} } }
|
||||
`))
|
||||
|
||||
var seenCmd *exec.Cmd
|
||||
restoreCmd := utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
seenCmd = cmd
|
||||
return &outputStub{}
|
||||
})
|
||||
defer restoreCmd()
|
||||
|
||||
output, err := RunCommand(repoCreateCmd, "repo create ORG/REPO")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo create`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.String(), "https://github.com/ORG/REPO\n")
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
if seenCmd == nil {
|
||||
t.Fatal("expected a command to run")
|
||||
}
|
||||
eq(t, strings.Join(seenCmd.Args, " "), "git remote add origin https://github.com/ORG/REPO.git")
|
||||
|
||||
var reqBody struct {
|
||||
Query string
|
||||
Variables struct {
|
||||
Input map[string]interface{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(http.Requests) != 2 {
|
||||
t.Fatalf("expected 2 HTTP requests, got %d", len(http.Requests))
|
||||
}
|
||||
|
||||
eq(t, http.Requests[0].URL.Path, "/users/ORG")
|
||||
|
||||
bodyBytes, _ := ioutil.ReadAll(http.Requests[1].Body)
|
||||
json.Unmarshal(bodyBytes, &reqBody)
|
||||
if orgID := reqBody.Variables.Input["ownerId"].(string); orgID != "ORGID" {
|
||||
t.Errorf("expected %q, got %q", "ORGID", orgID)
|
||||
}
|
||||
if _, teamSet := reqBody.Variables.Input["teamId"]; teamSet {
|
||||
t.Error("expected teamId not to be set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoCreate_orgWithTeam(t *testing.T) {
|
||||
ctx := context.NewBlank()
|
||||
ctx.SetBranch("master")
|
||||
initContext = func() context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
http := initFakeHTTP()
|
||||
http.StubResponse(200, bytes.NewBufferString(`
|
||||
{ "node_id": "TEAMID",
|
||||
"organization": { "node_id": "ORGID" }
|
||||
}
|
||||
`))
|
||||
http.StubResponse(200, bytes.NewBufferString(`
|
||||
{ "data": { "createRepository": {
|
||||
"repository": {
|
||||
"id": "REPOID",
|
||||
"url": "https://github.com/ORG/REPO"
|
||||
}
|
||||
} } }
|
||||
`))
|
||||
|
||||
var seenCmd *exec.Cmd
|
||||
restoreCmd := utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
|
||||
seenCmd = cmd
|
||||
return &outputStub{}
|
||||
})
|
||||
defer restoreCmd()
|
||||
|
||||
output, err := RunCommand(repoCreateCmd, "repo create ORG/REPO --team monkeys")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo create`: %v", err)
|
||||
}
|
||||
|
||||
eq(t, output.String(), "https://github.com/ORG/REPO\n")
|
||||
eq(t, output.Stderr(), "")
|
||||
|
||||
if seenCmd == nil {
|
||||
t.Fatal("expected a command to run")
|
||||
}
|
||||
eq(t, strings.Join(seenCmd.Args, " "), "git remote add origin https://github.com/ORG/REPO.git")
|
||||
|
||||
var reqBody struct {
|
||||
Query string
|
||||
Variables struct {
|
||||
Input map[string]interface{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(http.Requests) != 2 {
|
||||
t.Fatalf("expected 2 HTTP requests, got %d", len(http.Requests))
|
||||
}
|
||||
|
||||
eq(t, http.Requests[0].URL.Path, "/orgs/ORG/teams/monkeys")
|
||||
|
||||
bodyBytes, _ := ioutil.ReadAll(http.Requests[1].Body)
|
||||
json.Unmarshal(bodyBytes, &reqBody)
|
||||
if orgID := reqBody.Variables.Input["ownerId"].(string); orgID != "ORGID" {
|
||||
t.Errorf("expected %q, got %q", "ORGID", orgID)
|
||||
}
|
||||
if teamID := reqBody.Variables.Input["teamId"].(string); teamID != "TEAMID" {
|
||||
t.Errorf("expected %q, got %q", "TEAMID", teamID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoView(t *testing.T) {
|
||||
initBlankContext("OWNER/REPO", "master")
|
||||
http := initFakeHTTP()
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@ import (
|
|||
"github.com/cli/cli/utils"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// Version is dynamically set by the toolchain or overriden by the Makefile.
|
||||
// Version is dynamically set by the toolchain or overridden by the Makefile.
|
||||
var Version = "DEV"
|
||||
|
||||
// BuildDate is dynamically set at build time in the Makefile.
|
||||
|
|
@ -47,6 +48,9 @@ func init() {
|
|||
// RootCmd.PersistentFlags().BoolP("verbose", "V", false, "enable verbose output")
|
||||
|
||||
RootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
|
||||
if err == pflag.ErrHelp {
|
||||
return err
|
||||
}
|
||||
return &FlagError{Err: err}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue