Fix repo fork to use remote protocol if none configured

This commit is contained in:
William Martin 2024-05-08 14:41:26 +02:00
parent d0e436b369
commit 07e0ff7127
22 changed files with 151 additions and 97 deletions

View file

@ -58,16 +58,22 @@ func (c *cfg) get(hostname, key string) o.Option[string] {
return o.None[string]()
}
func (c *cfg) GetOrDefault(hostname, key string) o.Option[string] {
func (c *cfg) GetOrDefault(hostname, key string) o.Option[gh.ConfigEntry] {
if val := c.get(hostname, key); val.IsSome() {
return val
return o.Map(val, toConfigEntry(gh.ConfigUserProvided))
}
if defaultVal := defaultFor(key); defaultVal.IsSome() {
return defaultVal
return o.Map(defaultVal, toConfigEntry(gh.ConfigDefaultProvided))
}
return o.None[string]()
return o.None[gh.ConfigEntry]()
}
func toConfigEntry(source gh.ConfigSource) func(val string) gh.ConfigEntry {
return func(val string) gh.ConfigEntry {
return gh.ConfigEntry{Value: val, Source: source}
}
}
func (c *cfg) Set(hostname, key, value string) {
@ -95,32 +101,32 @@ func (c *cfg) Authentication() gh.AuthConfig {
return &AuthConfig{cfg: c.cfg}
}
func (c *cfg) Browser(hostname string) string {
func (c *cfg) Browser(hostname string) gh.ConfigEntry {
// Intentionally panic as this is a programmer error
return c.GetOrDefault(hostname, browserKey).Unwrap()
}
func (c *cfg) Editor(hostname string) string {
func (c *cfg) Editor(hostname string) gh.ConfigEntry {
// Intentionally panic as this is a programmer error
return c.GetOrDefault(hostname, editorKey).Unwrap()
}
func (c *cfg) GitProtocol(hostname string) string {
func (c *cfg) GitProtocol(hostname string) gh.ConfigEntry {
// Intentionally panic as this is a programmer error
return c.GetOrDefault(hostname, gitProtocolKey).Unwrap()
}
func (c *cfg) HTTPUnixSocket(hostname string) string {
func (c *cfg) HTTPUnixSocket(hostname string) gh.ConfigEntry {
// Intentionally panic as this is a programmer error
return c.GetOrDefault(hostname, httpUnixSocketKey).Unwrap()
}
func (c *cfg) Pager(hostname string) string {
func (c *cfg) Pager(hostname string) gh.ConfigEntry {
// Intentionally panic as this is a programmer error
return c.GetOrDefault(hostname, pagerKey).Unwrap()
}
func (c *cfg) Prompt(hostname string) string {
func (c *cfg) Prompt(hostname string) gh.ConfigEntry {
// Intentionally panic as this is a programmer error
return c.GetOrDefault(hostname, promptKey).Unwrap()
}
@ -523,7 +529,7 @@ var Options = []ConfigOption{
DefaultValue: "https",
AllowedValues: []string{"https", "ssh"},
CurrentValue: func(c gh.Config, hostname string) string {
return c.GitProtocol(hostname)
return c.GitProtocol(hostname).Value
},
},
{
@ -531,7 +537,7 @@ var Options = []ConfigOption{
Description: "the text editor program to use for authoring text",
DefaultValue: "",
CurrentValue: func(c gh.Config, hostname string) string {
return c.Editor(hostname)
return c.Editor(hostname).Value
},
},
{
@ -540,7 +546,7 @@ var Options = []ConfigOption{
DefaultValue: "enabled",
AllowedValues: []string{"enabled", "disabled"},
CurrentValue: func(c gh.Config, hostname string) string {
return c.Prompt(hostname)
return c.Prompt(hostname).Value
},
},
{
@ -548,7 +554,7 @@ var Options = []ConfigOption{
Description: "the terminal pager program to send standard output to",
DefaultValue: "",
CurrentValue: func(c gh.Config, hostname string) string {
return c.Pager(hostname)
return c.Pager(hostname).Value
},
},
{
@ -556,7 +562,7 @@ var Options = []ConfigOption{
Description: "the path to a Unix socket through which to make an HTTP connection",
DefaultValue: "",
CurrentValue: func(c gh.Config, hostname string) string {
return c.HTTPUnixSocket(hostname)
return c.HTTPUnixSocket(hostname).Value
},
},
{
@ -564,7 +570,7 @@ var Options = []ConfigOption{
Description: "the web browser to use for opening URLs",
DefaultValue: "",
CurrentValue: func(c gh.Config, hostname string) string {
return c.Browser(hostname)
return c.Browser(hostname).Value
},
},
}

View file

@ -1,10 +1,12 @@
package config
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cli/cli/v2/internal/gh"
ghConfig "github.com/cli/go-gh/v2/pkg/config"
)
@ -51,11 +53,12 @@ func TestGetOrDefaultApplicationDefaults(t *testing.T) {
cfg := newTestConfig()
// When we get a key that has no value, but has a default
optionalVal := cfg.GetOrDefault("", tt.key)
optionalEntry := cfg.GetOrDefault("", tt.key)
// Then there is an entry with the default value, and source set as default
require.True(t, optionalVal.IsSome(), "expected there to be a value")
require.Equal(t, tt.expectedDefault, optionalVal.Unwrap())
entry := optionalEntry.Expect(fmt.Sprintf("expected there to be a value for %s", tt.key))
require.Equal(t, tt.expectedDefault, entry.Value)
require.Equal(t, gh.ConfigDefaultProvided, entry.Source)
})
}
}
@ -65,10 +68,10 @@ func TestGetOrDefaultNonExistentKey(t *testing.T) {
cfg := newTestConfig()
// When we get a key that has no value
optionalVal := cfg.GetOrDefault("", "non-existent-key")
optionalEntry := cfg.GetOrDefault("", "non-existent-key")
// Then it returns a None variant
require.True(t, optionalVal.IsNone(), "expected there to be no value")
require.True(t, optionalEntry.IsNone(), "expected there to be no value")
}
func TestGetOrDefaultNonExistentHostSpecificKey(t *testing.T) {
@ -76,10 +79,10 @@ func TestGetOrDefaultNonExistentHostSpecificKey(t *testing.T) {
cfg := newTestConfig()
// When we get a key for a host that has no value
optionalVal := cfg.GetOrDefault("non-existent-host", "non-existent-key")
optionalEntry := cfg.GetOrDefault("non-existent-host", "non-existent-key")
// Then it returns a None variant
require.True(t, optionalVal.IsNone(), "expected there to be no value")
require.True(t, optionalEntry.IsNone(), "expected there to be no value")
}
func TestGetOrDefaultExistingTopLevelKey(t *testing.T) {
@ -88,11 +91,12 @@ func TestGetOrDefaultExistingTopLevelKey(t *testing.T) {
cfg.Set("", "top-level-key", "top-level-value")
// When we get that key
optionalVal := cfg.GetOrDefault("non-existent-host", "top-level-key")
optionalEntry := cfg.GetOrDefault("non-existent-host", "top-level-key")
// Then it returns a Some variant containing the correct value
require.True(t, optionalVal.IsSome(), "expected there to be a value")
require.Equal(t, "top-level-value", optionalVal.Unwrap())
// Then it returns a Some variant containing the correct value and a source of user
entry := optionalEntry.Expect("expected there to be a value")
require.Equal(t, "top-level-value", entry.Value)
require.Equal(t, gh.ConfigUserProvided, entry.Source)
}
func TestGetOrDefaultExistingHostSpecificKey(t *testing.T) {
@ -101,11 +105,12 @@ func TestGetOrDefaultExistingHostSpecificKey(t *testing.T) {
cfg.Set("github.com", "host-specific-key", "host-specific-value")
// When we get that key
optionalVal := cfg.GetOrDefault("github.com", "host-specific-key")
optionalEntry := cfg.GetOrDefault("github.com", "host-specific-key")
// Then it returns a Some variant containing the correct value
require.True(t, optionalVal.IsSome(), "expected there to be a value")
require.Equal(t, "host-specific-value", optionalVal.Unwrap())
// Then it returns a Some variant containing the correct value and a source of user
entry := optionalEntry.Expect("expected there to be a value")
require.Equal(t, "host-specific-value", entry.Value)
require.Equal(t, gh.ConfigUserProvided, entry.Source)
}
func TestGetOrDefaultHostnameSpecificKeyFallsBackToTopLevel(t *testing.T) {
@ -114,11 +119,13 @@ func TestGetOrDefaultHostnameSpecificKeyFallsBackToTopLevel(t *testing.T) {
cfg.Set("", "key", "value")
// When we get that key on a specific host
optionalVal := cfg.GetOrDefault("github.com", "key")
optionalEntry := cfg.GetOrDefault("github.com", "key")
// Then it returns a Some variant containing the correct value by falling back to the top level config
require.True(t, optionalVal.IsSome(), "expected there to be a value")
require.Equal(t, "value", optionalVal.Unwrap())
// Then it returns a Some variant containing the correct value by falling back
// to the top level config, with a source of user
entry := optionalEntry.Expect("expected there to be a value")
require.Equal(t, "value", entry.Value)
require.Equal(t, gh.ConfigUserProvided, entry.Source)
}
func TestFallbackConfig(t *testing.T) {

View file

@ -21,7 +21,7 @@ func NewFromString(cfgStr string) *ghmock.ConfigMock {
c := ghConfig.ReadFromString(cfgStr)
cfg := cfg{c}
mock := &ghmock.ConfigMock{}
mock.GetOrDefaultFunc = func(host, key string) o.Option[string] {
mock.GetOrDefaultFunc = func(host, key string) o.Option[gh.ConfigEntry] {
return cfg.GetOrDefault(host, key)
}
mock.SetFunc = func(host, key, value string) {
@ -52,22 +52,22 @@ func NewFromString(cfgStr string) *ghmock.ConfigMock {
},
}
}
mock.BrowserFunc = func(hostname string) string {
mock.BrowserFunc = func(hostname string) gh.ConfigEntry {
return cfg.Browser(hostname)
}
mock.EditorFunc = func(hostname string) string {
mock.EditorFunc = func(hostname string) gh.ConfigEntry {
return cfg.Editor(hostname)
}
mock.GitProtocolFunc = func(hostname string) string {
mock.GitProtocolFunc = func(hostname string) gh.ConfigEntry {
return cfg.GitProtocol(hostname)
}
mock.HTTPUnixSocketFunc = func(hostname string) string {
mock.HTTPUnixSocketFunc = func(hostname string) gh.ConfigEntry {
return cfg.HTTPUnixSocket(hostname)
}
mock.PagerFunc = func(hostname string) string {
mock.PagerFunc = func(hostname string) gh.ConfigEntry {
return cfg.Pager(hostname)
}
mock.PromptFunc = func(hostname string) string {
mock.PromptFunc = func(hostname string) gh.ConfigEntry {
return cfg.Prompt(hostname)
}
mock.VersionFunc = func() o.Option[string] {

View file

@ -14,27 +14,39 @@ import (
ghConfig "github.com/cli/go-gh/v2/pkg/config"
)
type ConfigSource string
const (
ConfigDefaultProvided ConfigSource = "default"
ConfigUserProvided ConfigSource = "user"
)
type ConfigEntry struct {
Value string
Source ConfigSource
}
// A Config implements persistent storage and modification of application configuration.
//
//go:generate moq -rm -pkg ghmock -out mock/config.go . Config
type Config interface {
// GetOrDefault provides primitive access for fetching configuration values, optionally scoped by host.
GetOrDefault(hostname string, key string) o.Option[string]
GetOrDefault(hostname string, key string) o.Option[ConfigEntry]
// Set provides primitive access for setting configuration values, optionally scoped by host.
Set(hostname string, key string, value string)
// Browser returns the configured browser, optionally scoped by host.
Browser(hostname string) string
Browser(hostname string) ConfigEntry
// Editor returns the configured editor, optionally scoped by host.
Editor(hostname string) string
Editor(hostname string) ConfigEntry
// GitProtocol returns the configured git protocol, optionally scoped by host.
GitProtocol(hostname string) string
GitProtocol(hostname string) ConfigEntry
// HTTPUnixSocket returns the configured HTTP unix socket, optionally scoped by host.
HTTPUnixSocket(hostname string) string
HTTPUnixSocket(hostname string) ConfigEntry
// Pager returns the configured Pager, optionally scoped by host.
Pager(hostname string) string
Pager(hostname string) ConfigEntry
// Prompt returns the configured prompt, optionally scoped by host.
Prompt(hostname string) string
Prompt(hostname string) ConfigEntry
// Aliases provides persistent storage and modification of command aliases.
Aliases() AliasConfig

View file

@ -25,31 +25,31 @@ var _ gh.Config = &ConfigMock{}
// AuthenticationFunc: func() gh.AuthConfig {
// panic("mock out the Authentication method")
// },
// BrowserFunc: func(hostname string) string {
// BrowserFunc: func(hostname string) gh.ConfigEntry {
// panic("mock out the Browser method")
// },
// CacheDirFunc: func() string {
// panic("mock out the CacheDir method")
// },
// EditorFunc: func(hostname string) string {
// EditorFunc: func(hostname string) gh.ConfigEntry {
// panic("mock out the Editor method")
// },
// GetOrDefaultFunc: func(hostname string, key string) o.Option[string] {
// GetOrDefaultFunc: func(hostname string, key string) o.Option[gh.ConfigEntry] {
// panic("mock out the GetOrDefault method")
// },
// GitProtocolFunc: func(hostname string) string {
// GitProtocolFunc: func(hostname string) gh.ConfigEntry {
// panic("mock out the GitProtocol method")
// },
// HTTPUnixSocketFunc: func(hostname string) string {
// HTTPUnixSocketFunc: func(hostname string) gh.ConfigEntry {
// panic("mock out the HTTPUnixSocket method")
// },
// MigrateFunc: func(migration gh.Migration) error {
// panic("mock out the Migrate method")
// },
// PagerFunc: func(hostname string) string {
// PagerFunc: func(hostname string) gh.ConfigEntry {
// panic("mock out the Pager method")
// },
// PromptFunc: func(hostname string) string {
// PromptFunc: func(hostname string) gh.ConfigEntry {
// panic("mock out the Prompt method")
// },
// SetFunc: func(hostname string, key string, value string) {
@ -75,31 +75,31 @@ type ConfigMock struct {
AuthenticationFunc func() gh.AuthConfig
// BrowserFunc mocks the Browser method.
BrowserFunc func(hostname string) string
BrowserFunc func(hostname string) gh.ConfigEntry
// CacheDirFunc mocks the CacheDir method.
CacheDirFunc func() string
// EditorFunc mocks the Editor method.
EditorFunc func(hostname string) string
EditorFunc func(hostname string) gh.ConfigEntry
// GetOrDefaultFunc mocks the GetOrDefault method.
GetOrDefaultFunc func(hostname string, key string) o.Option[string]
GetOrDefaultFunc func(hostname string, key string) o.Option[gh.ConfigEntry]
// GitProtocolFunc mocks the GitProtocol method.
GitProtocolFunc func(hostname string) string
GitProtocolFunc func(hostname string) gh.ConfigEntry
// HTTPUnixSocketFunc mocks the HTTPUnixSocket method.
HTTPUnixSocketFunc func(hostname string) string
HTTPUnixSocketFunc func(hostname string) gh.ConfigEntry
// MigrateFunc mocks the Migrate method.
MigrateFunc func(migration gh.Migration) error
// PagerFunc mocks the Pager method.
PagerFunc func(hostname string) string
PagerFunc func(hostname string) gh.ConfigEntry
// PromptFunc mocks the Prompt method.
PromptFunc func(hostname string) string
PromptFunc func(hostname string) gh.ConfigEntry
// SetFunc mocks the Set method.
SetFunc func(hostname string, key string, value string)
@ -250,7 +250,7 @@ func (mock *ConfigMock) AuthenticationCalls() []struct {
}
// Browser calls BrowserFunc.
func (mock *ConfigMock) Browser(hostname string) string {
func (mock *ConfigMock) Browser(hostname string) gh.ConfigEntry {
if mock.BrowserFunc == nil {
panic("ConfigMock.BrowserFunc: method is nil but Config.Browser was just called")
}
@ -309,7 +309,7 @@ func (mock *ConfigMock) CacheDirCalls() []struct {
}
// Editor calls EditorFunc.
func (mock *ConfigMock) Editor(hostname string) string {
func (mock *ConfigMock) Editor(hostname string) gh.ConfigEntry {
if mock.EditorFunc == nil {
panic("ConfigMock.EditorFunc: method is nil but Config.Editor was just called")
}
@ -341,7 +341,7 @@ func (mock *ConfigMock) EditorCalls() []struct {
}
// GetOrDefault calls GetOrDefaultFunc.
func (mock *ConfigMock) GetOrDefault(hostname string, key string) o.Option[string] {
func (mock *ConfigMock) GetOrDefault(hostname string, key string) o.Option[gh.ConfigEntry] {
if mock.GetOrDefaultFunc == nil {
panic("ConfigMock.GetOrDefaultFunc: method is nil but Config.GetOrDefault was just called")
}
@ -377,7 +377,7 @@ func (mock *ConfigMock) GetOrDefaultCalls() []struct {
}
// GitProtocol calls GitProtocolFunc.
func (mock *ConfigMock) GitProtocol(hostname string) string {
func (mock *ConfigMock) GitProtocol(hostname string) gh.ConfigEntry {
if mock.GitProtocolFunc == nil {
panic("ConfigMock.GitProtocolFunc: method is nil but Config.GitProtocol was just called")
}
@ -409,7 +409,7 @@ func (mock *ConfigMock) GitProtocolCalls() []struct {
}
// HTTPUnixSocket calls HTTPUnixSocketFunc.
func (mock *ConfigMock) HTTPUnixSocket(hostname string) string {
func (mock *ConfigMock) HTTPUnixSocket(hostname string) gh.ConfigEntry {
if mock.HTTPUnixSocketFunc == nil {
panic("ConfigMock.HTTPUnixSocketFunc: method is nil but Config.HTTPUnixSocket was just called")
}
@ -473,7 +473,7 @@ func (mock *ConfigMock) MigrateCalls() []struct {
}
// Pager calls PagerFunc.
func (mock *ConfigMock) Pager(hostname string) string {
func (mock *ConfigMock) Pager(hostname string) gh.ConfigEntry {
if mock.PagerFunc == nil {
panic("ConfigMock.PagerFunc: method is nil but Config.Pager was just called")
}
@ -505,7 +505,7 @@ func (mock *ConfigMock) PagerCalls() []struct {
}
// Prompt calls PromptFunc.
func (mock *ConfigMock) Prompt(hostname string) string {
func (mock *ConfigMock) Prompt(hostname string) gh.ConfigEntry {
if mock.PromptFunc == nil {
panic("ConfigMock.PromptFunc: method is nil but Config.Prompt was just called")
}

View file

@ -177,7 +177,7 @@ func refreshRun(opts *RefreshOptions) error {
Prompter: opts.Prompter,
GitClient: opts.GitClient,
}
gitProtocol := cfg.GitProtocol(hostname)
gitProtocol := cfg.GitProtocol(hostname).Value
if opts.Interactive && gitProtocol == "https" {
if err := credentialFlow.Prompt(hostname); err != nil {
return err

View file

@ -201,7 +201,7 @@ func statusRun(opts *StatusOptions) error {
}
var activeUser string
gitProtocol := cfg.GitProtocol(hostname)
gitProtocol := cfg.GitProtocol(hostname).Value
activeUserToken, activeUserTokenSource := authCfg.ActiveToken(hostname)
if authTokenWriteable(activeUserTokenSource) {
activeUser, _ = authCfg.ActiveUser(hostname)

View file

@ -64,12 +64,12 @@ func getRun(opts *GetOptions) error {
return nil
}
optionalValue := opts.Config.GetOrDefault(opts.Hostname, opts.Key)
if optionalValue.IsNone() {
optionalEntry := opts.Config.GetOrDefault(opts.Hostname, opts.Key)
if optionalEntry.IsNone() {
return nonExistentKeyError{key: opts.Key}
}
val := optionalValue.Unwrap()
val := optionalEntry.Unwrap().Value
if val != "" {
fmt.Fprintf(opts.IO.Out, "%s\n", val)
}

View file

@ -150,9 +150,10 @@ func Test_setRun(t *testing.T) {
assert.Equal(t, tt.stdout, stdout.String())
assert.Equal(t, tt.stderr, stderr.String())
optionalValue := tt.input.Config.GetOrDefault(tt.input.Hostname, tt.input.Key)
assert.True(t, optionalValue.IsSome(), "expected value to be set")
assert.Equal(t, tt.expectedValue, optionalValue.Unwrap())
optionalEntry := tt.input.Config.GetOrDefault(tt.input.Hostname, tt.input.Key)
entry := optionalEntry.Expect("expected a value to be set")
assert.Equal(t, tt.expectedValue, entry.Value)
assert.Equal(t, gh.ConfigUserProvided, entry.Source)
})
}
}

View file

@ -347,7 +347,7 @@ func writeManifest(dir, name string, data []byte) (writeErr error) {
}
func (m *Manager) installGit(repo ghrepo.Interface, target string) error {
protocol := m.config.GitProtocol(repo.RepoHost())
protocol := m.config.GitProtocol(repo.RepoHost()).Value
cloneURL := ghrepo.FormatRemoteURL(repo, protocol)
var commitSHA string

View file

@ -185,7 +185,7 @@ func ioStreams(f *cmdutil.Factory) *iostreams.IOStreams {
if _, ghPromptDisabled := os.LookupEnv("GH_PROMPT_DISABLED"); ghPromptDisabled {
io.SetNeverPrompt(true)
} else if prompt := cfg.Prompt(""); prompt == "disabled" {
} else if prompt := cfg.Prompt(""); prompt.Value == "disabled" {
io.SetNeverPrompt(true)
}
@ -195,8 +195,8 @@ func ioStreams(f *cmdutil.Factory) *iostreams.IOStreams {
// 3. PAGER
if ghPager, ghPagerExists := os.LookupEnv("GH_PAGER"); ghPagerExists {
io.SetPager(ghPager)
} else if pager := cfg.Pager(""); pager != "" {
io.SetPager(pager)
} else if pager := cfg.Pager(""); pager.Value != "" {
io.SetPager(pager.Value)
}
return io

View file

@ -80,7 +80,7 @@ func cloneRun(opts *CloneOptions) error {
return err
}
hostname, _ := cfg.Authentication().DefaultHost()
protocol := cfg.GitProtocol(hostname)
protocol := cfg.GitProtocol(hostname).Value
gistURL = formatRemoteURL(hostname, gistURL, protocol)
}

View file

@ -84,7 +84,7 @@ func checkoutRun(opts *CheckoutOptions) error {
if err != nil {
return err
}
protocol := cfg.GitProtocol(baseRepo.RepoHost())
protocol := cfg.GitProtocol(baseRepo.RepoHost()).Value
remotes, err := opts.Remotes()
if err != nil {

View file

@ -870,7 +870,7 @@ func handlePush(opts CreateOptions, ctx CreateContext) error {
return err
}
cloneProtocol := cfg.GitProtocol(headRepo.RepoHost())
cloneProtocol := cfg.GitProtocol(headRepo.RepoHost()).Value
headRepoURL := ghrepo.FormatRemoteURL(headRepo, cloneProtocol)
gitClient := ctx.GitClient
origin, _ := remotes.FindByName("origin")

View file

@ -153,7 +153,7 @@ func cloneRun(opts *CloneOptions) error {
return err
}
protocol = cfg.GitProtocol(repo.RepoHost())
protocol = cfg.GitProtocol(repo.RepoHost()).Value
}
wantsWiki := strings.HasSuffix(repo.RepoName(), ".wiki")
@ -187,7 +187,7 @@ func cloneRun(opts *CloneOptions) error {
// If the repo is a fork, add the parent as an upstream remote and set the parent as the default repo.
if canonicalRepo.Parent != nil {
protocol := cfg.GitProtocol(canonicalRepo.Parent.RepoHost())
protocol := cfg.GitProtocol(canonicalRepo.Parent.RepoHost()).Value
upstreamURL := ghrepo.FormatRemoteURL(canonicalRepo.Parent, protocol)
upstreamName := opts.UpstreamName

View file

@ -396,7 +396,7 @@ func createFromScratch(opts *CreateOptions) error {
}
if opts.Clone {
protocol := cfg.GitProtocol(repo.RepoHost())
protocol := cfg.GitProtocol(repo.RepoHost()).Value
remoteURL := ghrepo.FormatRemoteURL(repo, protocol)
if !opts.AddReadme && opts.LicenseTemplate == "" && opts.GitIgnoreTemplate == "" && opts.Template == "" {
@ -494,7 +494,7 @@ func createFromTemplate(opts *CreateOptions) error {
}
if opts.Clone {
protocol := cfg.GitProtocol(repo.RepoHost())
protocol := cfg.GitProtocol(repo.RepoHost()).Value
remoteURL := ghrepo.FormatRemoteURL(repo, protocol)
if err := cloneWithRetry(opts, remoteURL, templateRepoMainBranch); err != nil {
@ -617,7 +617,7 @@ func createFromLocal(opts *CreateOptions) error {
fmt.Fprintln(stdout, repo.URL)
}
protocol := cfg.GitProtocol(repo.RepoHost())
protocol := cfg.GitProtocol(repo.RepoHost()).Value
remoteURL := ghrepo.FormatRemoteURL(repo, protocol)
if opts.Interactive {

View file

@ -243,7 +243,9 @@ func forkRun(opts *ForkOptions) error {
if err != nil {
return err
}
protocol := cfg.GitProtocol(repoToFork.RepoHost())
protocolConfig := cfg.GitProtocol(repoToFork.RepoHost())
protocolIsConfiguredByUser := protocolConfig.Source == gh.ConfigUserProvided
protocol := protocolConfig.Value
gitClient := opts.GitClient
ctx := context.Background()
@ -254,7 +256,7 @@ func forkRun(opts *ForkOptions) error {
return err
}
if protocol == "" { // user has no set preference
if !protocolIsConfiguredByUser {
if remote, err := remotes.FindByRepo(repoToFork.RepoOwner(), repoToFork.RepoName()); err == nil {
scheme := ""
if remote.FetchURL != nil {

View file

@ -234,6 +234,9 @@ func TestRepoFork(t *testing.T) {
Repo: ghrepo.New("OWNER", "REPO"),
},
},
cfgStubs: func(_ *testing.T, c gh.Config) {
c.Set("", "git_protocol", "https")
},
httpStubs: forkPost,
execStubs: func(cs *run.CommandStubber) {
cs.Register(`git remote add fork https://github\.com/someone/REPO\.git`, 0, "")
@ -255,9 +258,6 @@ func TestRepoFork(t *testing.T) {
Repo: ghrepo.New("OWNER", "REPO"),
},
},
cfgStubs: func(_ *testing.T, c gh.Config) {
c.Set("", "git_protocol", "")
},
httpStubs: forkPost,
execStubs: func(cs *run.CommandStubber) {
cs.Register(`git remote add fork git@github\.com:someone/REPO\.git`, 0, "")

View file

@ -153,7 +153,7 @@ func updateRemote(repo ghrepo.Interface, renamed ghrepo.Interface, opts *RenameO
return nil, err
}
protocol := cfg.GitProtocol(repo.RepoHost())
protocol := cfg.GitProtocol(repo.RepoHost()).Value
remotes, err := opts.Remotes()
if err != nil {

View file

@ -16,7 +16,7 @@ func DetermineEditor(cf func() (gh.Config, error)) (string, error) {
if err != nil {
return "", fmt.Errorf("could not read config: %w", err)
}
editorCommand = cfg.Editor("")
editorCommand = cfg.Editor("").Value
}
return editorCommand, nil

View file

@ -117,3 +117,11 @@ func (o Option[T]) Expect(message string) T {
panic(message)
}
func Map[T, U any](o Option[T], f func(T) U) Option[U] {
if o.present {
return Some(f(o.value))
}
return None[U]()
}

View file

@ -99,6 +99,19 @@ func ExampleOption_Expect() {
// Output: 4
}
func ExampleMap() {
fmt.Println(o.Map(o.Some(2), double))
fmt.Println(o.Map(o.None[int](), double))
// Output:
// Some(4)
// None
}
func double(i int) int {
return i * 2
}
func TestSomeStringer(t *testing.T) {
require.Equal(t, fmt.Sprintf("%s", o.Some("foo")), "Some(foo)") //nolint:gosimple
require.Equal(t, fmt.Sprintf("%s", o.Some(42)), "Some(42)") //nolint:gosimple
@ -179,3 +192,8 @@ func TestNoneExpect(t *testing.T) {
o.None[int]().Expect("oops")
t.Error("did not panic")
}
func TestMap(t *testing.T) {
require.Equal(t, o.Map(o.Some(2), double), o.Some(4))
require.True(t, o.Map(o.None[int](), double).IsNone())
}