switch to alternate method for determining if repo already forked

This commit is contained in:
vilmibm 2020-02-27 16:43:44 -06:00
parent 115bf37bbd
commit 7fad2d05fb
6 changed files with 54 additions and 58 deletions

View file

@ -6,16 +6,18 @@ import (
"fmt"
"sort"
"strings"
"time"
"github.com/cli/cli/internal/ghrepo"
)
// Repository contains information about a GitHub repo
type Repository struct {
ID string
Name string
CloneURL string
Owner RepositoryOwner
ID string
Name string
CloneURL string
CreatedAt time.Time
Owner RepositoryOwner
IsPrivate bool
HasIssuesEnabled bool
@ -211,10 +213,11 @@ func RepoNetwork(client *Client, repos []ghrepo.Interface) (RepoNetworkResult, e
// repositoryV3 is the repository result from GitHub API v3
type repositoryV3 struct {
NodeID string
Name string
CloneURL string `json:"clone_url"`
Owner struct {
NodeID string
Name string
CreatedAt time.Time `json:"created_at"`
CloneURL string `json:"clone_url"`
Owner struct {
Login string
}
}
@ -230,9 +233,10 @@ func ForkRepo(client *Client, repo ghrepo.Interface) (*Repository, error) {
}
return &Repository{
ID: result.NodeID,
Name: result.Name,
CloneURL: result.CloneURL,
ID: result.NodeID,
Name: result.Name,
CloneURL: result.CloneURL,
CreatedAt: result.CreatedAt,
Owner: RepositoryOwner{
Login: result.Owner.Login,
},

View file

@ -5,6 +5,7 @@ import (
"net/url"
"os"
"strings"
"time"
"github.com/cli/cli/api"
"github.com/cli/cli/git"
@ -84,6 +85,10 @@ 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)
@ -148,23 +153,25 @@ func repoFork(cmd *cobra.Command, args []string) error {
}
possibleFork := ghrepo.New(authLogin, toFork.RepoName())
exists, err := api.GitHubRepoExists(apiClient, possibleFork)
if err != nil {
s.Stop()
return fmt.Errorf("problem with API request: %w", err)
}
if exists {
s.Stop()
fmt.Fprintf(out, redX+" ")
return fmt.Errorf("%s already exists", utils.Bold(ghrepo.FullName(possibleFork)))
}
forkedRepo, err := api.ForkRepo(apiClient, toFork)
if err != nil {
s.Stop()
return fmt.Errorf("failed to fork: %w", err)
}
// 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 {
s.Stop()
fmt.Fprintf(out, redX+" ")
return fmt.Errorf("%s already exists", utils.Bold(ghrepo.FullName(possibleFork)))
}
s.Stop()
fmt.Fprintf(out, "%s Created fork %s\n", greenCheck, utils.Bold(ghrepo.FullName(forkedRepo)))

View file

@ -5,6 +5,7 @@ import (
"regexp"
"strings"
"testing"
"time"
"github.com/cli/cli/context"
"github.com/cli/cli/utils"
@ -23,7 +24,7 @@ func TestRepoFork_already_forked(t *testing.T) {
}
http := initFakeHTTP()
http.StubRepoResponse("OWNER", "REPO")
defer http.StubWithFixture(200, "repo.json")()
defer http.StubWithFixture(200, "forkResult.json")()
_, err := RunCommand(repoForkCmd, "repo fork --remote=false")
if err == nil {
@ -34,11 +35,21 @@ func TestRepoFork_already_forked(t *testing.T) {
}
}
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, "repoNotFound.json")()
defer http.StubWithFixture(200, "forkResult.json")()
output, err := RunCommand(repoForkCmd, "repo fork --remote=false")
@ -75,8 +86,8 @@ func TestRepoFork_outside(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer stubSince(2 * time.Second)()
http := initFakeHTTP()
defer http.StubWithFixture(200, "repoNotFound.json")()
defer http.StubWithFixture(200, "forkResult.json")()
output, err := RunCommand(repoForkCmd, tt.args)
@ -101,9 +112,9 @@ func TestRepoFork_outside(t *testing.T) {
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, "repoNotFound.json")()
defer http.StubWithFixture(200, "forkResult.json")()
var seenCmds []*exec.Cmd
@ -141,8 +152,8 @@ func TestRepoFork_in_parent_yes(t *testing.T) {
}
func TestRepoFork_outside_yes(t *testing.T) {
defer stubSince(2 * time.Second)()
http := initFakeHTTP()
defer http.StubWithFixture(200, "repoNotFound.json")()
defer http.StubWithFixture(200, "forkResult.json")()
var seenCmd *exec.Cmd
@ -173,8 +184,8 @@ func TestRepoFork_outside_yes(t *testing.T) {
}
func TestRepoFork_outside_survey_yes(t *testing.T) {
defer stubSince(2 * time.Second)()
http := initFakeHTTP()
defer http.StubWithFixture(200, "repoNotFound.json")()
defer http.StubWithFixture(200, "forkResult.json")()
var seenCmd *exec.Cmd
@ -212,8 +223,8 @@ func TestRepoFork_outside_survey_yes(t *testing.T) {
}
func TestRepoFork_outside_survey_no(t *testing.T) {
defer stubSince(2 * time.Second)()
http := initFakeHTTP()
defer http.StubWithFixture(200, "repoNotFound.json")()
defer http.StubWithFixture(200, "forkResult.json")()
cmdRun := false
@ -251,9 +262,9 @@ func TestRepoFork_outside_survey_no(t *testing.T) {
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, "repoNotFound.json")()
defer http.StubWithFixture(200, "forkResult.json")()
var seenCmds []*exec.Cmd
@ -299,9 +310,9 @@ func TestRepoFork_in_parent_survey_yes(t *testing.T) {
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, "repoNotFound.json")()
defer http.StubWithFixture(200, "forkResult.json")()
cmdRun := false

View file

@ -2,6 +2,7 @@
"node_id": "123",
"name": "REPO",
"clone_url": "https://github.com/someone/repo.git",
"created_at": "2011-01-26T19:01:12Z",
"owner": {
"login": "someone"
}

View file

@ -1,7 +0,0 @@
{
"data": {
"repository": {
"id": "MDEwOlJlcG9zaXRvcnkyMTI2MTMwNDk="
}
}
}

View file

@ -1,20 +0,0 @@
{
"data": {
"repository": null
},
"errors": [
{
"type": "NOT_FOUND",
"path": [
"repository"
],
"locations": [
{
"line": 2,
"column": 3
}
],
"message": "Could not resolve to a Repository with the name 'REPO'."
}
]
}