Merge pull request #5916 from cli/fork-without-rename
repo fork: directly fork under the desired name
This commit is contained in:
commit
1037917d67
7 changed files with 74 additions and 54 deletions
|
|
@ -500,13 +500,16 @@ type repositoryV3 struct {
|
|||
}
|
||||
|
||||
// ForkRepo forks the repository on GitHub and returns the new repository
|
||||
func ForkRepo(client *Client, repo ghrepo.Interface, org string) (*Repository, error) {
|
||||
func ForkRepo(client *Client, repo ghrepo.Interface, org, newName string) (*Repository, error) {
|
||||
path := fmt.Sprintf("repos/%s/forks", ghrepo.FullName(repo))
|
||||
|
||||
params := map[string]interface{}{}
|
||||
if org != "" {
|
||||
params["organization"] = org
|
||||
}
|
||||
if newName != "" {
|
||||
params["name"] = newName
|
||||
}
|
||||
|
||||
body := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(body)
|
||||
|
|
|
|||
|
|
@ -680,7 +680,7 @@ func handlePush(opts CreateOptions, ctx CreateContext) error {
|
|||
// one by forking the base repository
|
||||
if headRepo == nil && ctx.IsPushEnabled {
|
||||
opts.IO.StartProgressIndicator()
|
||||
headRepo, err = api.ForkRepo(client, ctx.BaseRepo, "")
|
||||
headRepo, err = api.ForkRepo(client, ctx.BaseRepo, "", "")
|
||||
opts.IO.StopProgressIndicator()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error forking repo: %w", err)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/http"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
|
|
@ -16,6 +15,7 @@ import (
|
|||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/run"
|
||||
"github.com/cli/cli/v2/pkg/cmd/repo/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
|
|
@ -816,9 +816,9 @@ func interactiveSource() (string, error) {
|
|||
}
|
||||
|
||||
func confirmSubmission(repoWithOwner, visibility string) error {
|
||||
targetRepo := normalizeRepoName(repoWithOwner)
|
||||
targetRepo := shared.NormalizeRepoName(repoWithOwner)
|
||||
if idx := strings.IndexRune(repoWithOwner, '/'); idx > 0 {
|
||||
targetRepo = repoWithOwner[0:idx+1] + normalizeRepoName(repoWithOwner[idx+1:])
|
||||
targetRepo = repoWithOwner[0:idx+1] + shared.NormalizeRepoName(repoWithOwner[idx+1:])
|
||||
}
|
||||
var answer struct {
|
||||
ConfirmSubmit bool
|
||||
|
|
@ -838,8 +838,3 @@ func confirmSubmission(repoWithOwner, visibility string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// normalizeRepoName takes in the repo name the user inputted and normalizes it using the same logic as GitHub (GitHub.com/new)
|
||||
func normalizeRepoName(repoName string) string {
|
||||
return strings.TrimSuffix(regexp.MustCompile(`[^\w._-]+`).ReplaceAllString(repoName, "-"), ".git")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -495,44 +495,3 @@ func Test_createRun(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getModifiedNormalizedName(t *testing.T) {
|
||||
// confirmed using GitHub.com/new
|
||||
tests := []struct {
|
||||
LocalName string
|
||||
NormalizedName string
|
||||
}{
|
||||
{
|
||||
LocalName: "cli",
|
||||
NormalizedName: "cli",
|
||||
},
|
||||
{
|
||||
LocalName: "cli.git",
|
||||
NormalizedName: "cli",
|
||||
},
|
||||
{
|
||||
LocalName: "@-#$^",
|
||||
NormalizedName: "---",
|
||||
},
|
||||
{
|
||||
LocalName: "[cli]",
|
||||
NormalizedName: "-cli-",
|
||||
},
|
||||
{
|
||||
LocalName: "Hello World, I'm a new repo!",
|
||||
NormalizedName: "Hello-World-I-m-a-new-repo-",
|
||||
},
|
||||
{
|
||||
LocalName: " @E3H*(#$#_$-ZVp,n.7lGq*_eMa-(-zAZSJYg!",
|
||||
NormalizedName: "-E3H-_--ZVp-n.7lGq-_eMa---zAZSJYg-",
|
||||
},
|
||||
{
|
||||
LocalName: "I'm a crazy .git repo name .git.git .git",
|
||||
NormalizedName: "I-m-a-crazy-.git-repo-name-.git.git-",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
output := normalizeRepoName(tt.LocalName)
|
||||
assert.Equal(t, tt.NormalizedName, output)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/run"
|
||||
"github.com/cli/cli/v2/pkg/cmd/repo/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
|
|
@ -179,7 +180,7 @@ func forkRun(opts *ForkOptions) error {
|
|||
apiClient := api.NewClientFromHTTP(httpClient)
|
||||
|
||||
opts.IO.StartProgressIndicator()
|
||||
forkedRepo, err := api.ForkRepo(apiClient, repoToFork, opts.Organization)
|
||||
forkedRepo, err := api.ForkRepo(apiClient, repoToFork, opts.Organization, opts.ForkName)
|
||||
opts.IO.StopProgressIndicator()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fork: %w", err)
|
||||
|
|
@ -206,8 +207,8 @@ func forkRun(opts *ForkOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Rename the forked repo if ForkName is specified in opts.
|
||||
if opts.ForkName != "" {
|
||||
// Rename the new repo if necessary
|
||||
if opts.ForkName != "" && !strings.EqualFold(forkedRepo.RepoName(), shared.NormalizeRepoName(opts.ForkName)) {
|
||||
forkedRepo, err = api.RenameRepo(apiClient, forkedRepo, opts.ForkName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not rename fork: %w", err)
|
||||
|
|
|
|||
14
pkg/cmd/repo/shared/repo.go
Normal file
14
pkg/cmd/repo/shared/repo.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package shared
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var invalidCharactersRE = regexp.MustCompile(`[^\w._-]+`)
|
||||
|
||||
// NormalizeRepoName takes in the repo name the user inputted and normalizes it using the same logic as GitHub (GitHub.com/new)
|
||||
func NormalizeRepoName(repoName string) string {
|
||||
newName := invalidCharactersRE.ReplaceAllString(repoName, "-")
|
||||
return strings.TrimSuffix(newName, ".git")
|
||||
}
|
||||
48
pkg/cmd/repo/shared/repo_test.go
Normal file
48
pkg/cmd/repo/shared/repo_test.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package shared
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNormalizeRepoName(t *testing.T) {
|
||||
// confirmed using GitHub.com/new
|
||||
tests := []struct {
|
||||
LocalName string
|
||||
NormalizedName string
|
||||
}{
|
||||
{
|
||||
LocalName: "cli",
|
||||
NormalizedName: "cli",
|
||||
},
|
||||
{
|
||||
LocalName: "cli.git",
|
||||
NormalizedName: "cli",
|
||||
},
|
||||
{
|
||||
LocalName: "@-#$^",
|
||||
NormalizedName: "---",
|
||||
},
|
||||
{
|
||||
LocalName: "[cli]",
|
||||
NormalizedName: "-cli-",
|
||||
},
|
||||
{
|
||||
LocalName: "Hello World, I'm a new repo!",
|
||||
NormalizedName: "Hello-World-I-m-a-new-repo-",
|
||||
},
|
||||
{
|
||||
LocalName: " @E3H*(#$#_$-ZVp,n.7lGq*_eMa-(-zAZSJYg!",
|
||||
NormalizedName: "-E3H-_--ZVp-n.7lGq-_eMa---zAZSJYg-",
|
||||
},
|
||||
{
|
||||
LocalName: "I'm a crazy .git repo name .git.git .git",
|
||||
NormalizedName: "I-m-a-crazy-.git-repo-name-.git.git-",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
output := NormalizeRepoName(tt.LocalName)
|
||||
if output != tt.NormalizedName {
|
||||
t.Errorf("Expected %q, got %q", tt.NormalizedName, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue