Merge branch 'trunk' into dependabot/go_modules/github.com/cpuguy83/go-md2man/v2-2.0.5
This commit is contained in:
commit
be7631c7c8
14 changed files with 237 additions and 29 deletions
2
go.mod
2
go.mod
|
|
@ -25,7 +25,7 @@ require (
|
|||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-version v1.3.0
|
||||
github.com/henvic/httpretty v0.1.3
|
||||
github.com/henvic/httpretty v0.1.4
|
||||
github.com/in-toto/attestation v1.1.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -252,8 +252,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
|||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/vault/api v1.12.2 h1:7YkCTE5Ni90TcmYHDBExdt4WGJxhpzaHqR6uGbQb/rE=
|
||||
github.com/hashicorp/vault/api v1.12.2/go.mod h1:LSGf1NGT1BnvFFnKVtnvcaLBM2Lz+gJdpL6HUYed8KE=
|
||||
github.com/henvic/httpretty v0.1.3 h1:4A6vigjz6Q/+yAfTD4wqipCv+Px69C7Th/NhT0ApuU8=
|
||||
github.com/henvic/httpretty v0.1.3/go.mod h1:UUEv7c2kHZ5SPQ51uS3wBpzPDibg2U3Y+IaXyHy5GBg=
|
||||
github.com/henvic/httpretty v0.1.4 h1:Jo7uwIRWVFxkqOnErcoYfH90o3ddQyVrSANeS4cxYmU=
|
||||
github.com/henvic/httpretty v0.1.4/go.mod h1:Dn60sQTZfbt2dYsdUSNsCljyF4AfdqnuJFDLJA1I4AM=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
|
||||
|
|
|
|||
|
|
@ -52,8 +52,32 @@ func TestTokenFromKeyringForUserErrorsIfUsernameIsBlank(t *testing.T) {
|
|||
require.ErrorContains(t, err, "username cannot be blank")
|
||||
}
|
||||
|
||||
func TestHasActiveToken(t *testing.T) {
|
||||
// Given the user has logged in for a host
|
||||
authCfg := newTestAuthConfig(t)
|
||||
_, err := authCfg.Login("github.com", "test-user", "test-token", "", false)
|
||||
require.NoError(t, err)
|
||||
|
||||
// When we check if that host has an active token
|
||||
hasActiveToken := authCfg.HasActiveToken("github.com")
|
||||
|
||||
// Then there is an active token
|
||||
require.True(t, hasActiveToken, "expected there to be an active token")
|
||||
}
|
||||
|
||||
func TestHasNoActiveToken(t *testing.T) {
|
||||
// Given there are no users logged in for a host
|
||||
authCfg := newTestAuthConfig(t)
|
||||
|
||||
// When we check if any host has an active token
|
||||
hasActiveToken := authCfg.HasActiveToken("github.com")
|
||||
|
||||
// Then there is no active token
|
||||
require.False(t, hasActiveToken, "expected there to be no active token")
|
||||
}
|
||||
|
||||
func TestTokenStoredInConfig(t *testing.T) {
|
||||
// When the user has logged in insecurely
|
||||
// Given the user has logged in insecurely
|
||||
authCfg := newTestAuthConfig(t)
|
||||
_, err := authCfg.Login("github.com", "test-user", "test-token", "", false)
|
||||
require.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -217,6 +217,12 @@ func (c *AuthConfig) ActiveToken(hostname string) (string, string) {
|
|||
return token, source
|
||||
}
|
||||
|
||||
// HasActiveToken returns true when a token for the hostname is present.
|
||||
func (c *AuthConfig) HasActiveToken(hostname string) bool {
|
||||
token, _ := c.ActiveToken(hostname)
|
||||
return token != ""
|
||||
}
|
||||
|
||||
// HasEnvToken returns true when a token has been specified in an
|
||||
// environment variable, else returns false.
|
||||
func (c *AuthConfig) HasEnvToken() bool {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ type Migration interface {
|
|||
// with knowledge on how to access encrypted storage when neccesarry.
|
||||
// Behavior is scoped to authentication specific tasks.
|
||||
type AuthConfig interface {
|
||||
// HasActiveToken returns true when a token for the hostname is present.
|
||||
HasActiveToken(hostname string) bool
|
||||
|
||||
// ActiveToken will retrieve the active auth token for the given hostname, searching environment variables,
|
||||
// general configuration, and finally encrypted storage.
|
||||
ActiveToken(hostname string) (token string, source string)
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ func (p *surveyPrompter) InputHostname() (string, error) {
|
|||
var result string
|
||||
err := p.ask(
|
||||
&survey.Input{
|
||||
Message: "GHE hostname:",
|
||||
Message: "Hostname:",
|
||||
}, &result, survey.WithValidator(func(v interface{}) error {
|
||||
return ghinstance.HostnameValidator(v.(string))
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -69,6 +69,15 @@ func NewTrustedRootCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Com
|
|||
}
|
||||
|
||||
if ghinstance.IsTenancy(opts.Hostname) {
|
||||
c, err := f.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !c.Authentication().HasActiveToken(opts.Hostname) {
|
||||
return fmt.Errorf("not authenticated with %s", opts.Hostname)
|
||||
}
|
||||
|
||||
hc, err := f.HttpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -94,6 +103,7 @@ func NewTrustedRootCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Com
|
|||
},
|
||||
}
|
||||
|
||||
cmdutil.DisableAuthCheck(&trustedRootCmd)
|
||||
trustedRootCmd.Flags().StringVarP(&opts.TufUrl, "tuf-url", "", "", "URL to the TUF repository mirror")
|
||||
trustedRootCmd.Flags().StringVarP(&opts.TufRootPath, "tuf-root", "", "", "Path to the TUF root.json file on disk")
|
||||
trustedRootCmd.MarkFlagsRequiredTogether("tuf-url", "tuf-root")
|
||||
|
|
@ -116,6 +126,12 @@ func getTrustedRoot(makeTUF tufClientInstantiator, opts *Options) error {
|
|||
// Disable local caching, so we get up-to-date response from TUF repository
|
||||
tufOpt.CacheValidity = 0
|
||||
|
||||
// Target will be either the default trusted root, or the trust domain-qualified one
|
||||
ghTR := defaultTR
|
||||
if opts.TrustDomain != "" {
|
||||
ghTR = fmt.Sprintf("%s.%s", opts.TrustDomain, defaultTR)
|
||||
}
|
||||
|
||||
if opts.TufUrl != "" && opts.TufRootPath != "" {
|
||||
tufRoot, err := os.ReadFile(opts.TufRootPath)
|
||||
if err != nil {
|
||||
|
|
@ -126,7 +142,7 @@ func getTrustedRoot(makeTUF tufClientInstantiator, opts *Options) error {
|
|||
tufOpt.RepositoryBaseURL = opts.TufUrl
|
||||
tufOptions = append(tufOptions, tufConfig{
|
||||
tufOptions: tufOpt,
|
||||
targets: []string{defaultTR},
|
||||
targets: []string{ghTR},
|
||||
})
|
||||
} else {
|
||||
// Get from both Sigstore public good and GitHub private instance
|
||||
|
|
@ -137,14 +153,9 @@ func getTrustedRoot(makeTUF tufClientInstantiator, opts *Options) error {
|
|||
|
||||
tufOpt = verification.GitHubTUFOptions()
|
||||
tufOpt.CacheValidity = 0
|
||||
targets := []string{defaultTR}
|
||||
if opts.TrustDomain != "" {
|
||||
targets = append(targets, fmt.Sprintf("%s.%s",
|
||||
opts.TrustDomain, defaultTR))
|
||||
}
|
||||
tufOptions = append(tufOptions, tufConfig{
|
||||
tufOptions: tufOpt,
|
||||
targets: targets,
|
||||
targets: []string{ghTR},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package trustedroot
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
|
@ -10,8 +11,13 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/gh"
|
||||
ghmock "github.com/cli/cli/v2/internal/gh/mock"
|
||||
"github.com/cli/cli/v2/pkg/cmd/attestation/api"
|
||||
"github.com/cli/cli/v2/pkg/cmd/attestation/test"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/httpmock"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
)
|
||||
|
||||
|
|
@ -19,6 +25,9 @@ func TestNewTrustedRootCmd(t *testing.T) {
|
|||
testIO, _, _, _ := iostreams.Test()
|
||||
f := &cmdutil.Factory{
|
||||
IOStreams: testIO,
|
||||
Config: func() (gh.Config, error) {
|
||||
return &ghmock.ConfigMock{}, nil
|
||||
},
|
||||
}
|
||||
|
||||
testcases := []struct {
|
||||
|
|
@ -72,6 +81,83 @@ func TestNewTrustedRootCmd(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewTrustedRootWithTenancy(t *testing.T) {
|
||||
testIO, _, _, _ := iostreams.Test()
|
||||
var testReg httpmock.Registry
|
||||
var metaResp = api.MetaResponse{
|
||||
Domains: api.Domain{
|
||||
ArtifactAttestations: api.ArtifactAttestations{
|
||||
TrustDomain: "foo",
|
||||
},
|
||||
},
|
||||
}
|
||||
testReg.Register(httpmock.REST(http.MethodGet, "meta"),
|
||||
httpmock.StatusJSONResponse(200, &metaResp))
|
||||
|
||||
httpClientFunc := func() (*http.Client, error) {
|
||||
reg := &testReg
|
||||
client := &http.Client{}
|
||||
httpmock.ReplaceTripper(client, reg)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
cli := "--hostname foo-bar.ghe.com"
|
||||
|
||||
t.Run("Host with NO auth configured", func(t *testing.T) {
|
||||
f := &cmdutil.Factory{
|
||||
IOStreams: testIO,
|
||||
Config: func() (gh.Config, error) {
|
||||
return &ghmock.ConfigMock{
|
||||
AuthenticationFunc: func() gh.AuthConfig {
|
||||
return &stubAuthConfig{hasActiveToken: false}
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd := NewTrustedRootCmd(f, func(_ *Options) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
argv := strings.Split(cli, " ")
|
||||
cmd.SetArgs(argv)
|
||||
cmd.SetIn(&bytes.Buffer{})
|
||||
cmd.SetOut(&bytes.Buffer{})
|
||||
cmd.SetErr(&bytes.Buffer{})
|
||||
_, err := cmd.ExecuteC()
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.ErrorContains(t, err, "not authenticated")
|
||||
})
|
||||
|
||||
t.Run("Host with auth configured", func(t *testing.T) {
|
||||
f := &cmdutil.Factory{
|
||||
IOStreams: testIO,
|
||||
Config: func() (gh.Config, error) {
|
||||
return &ghmock.ConfigMock{
|
||||
AuthenticationFunc: func() gh.AuthConfig {
|
||||
return &stubAuthConfig{hasActiveToken: true}
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
HttpClient: httpClientFunc,
|
||||
}
|
||||
|
||||
cmd := NewTrustedRootCmd(f, func(_ *Options) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
argv := strings.Split(cli, " ")
|
||||
cmd.SetArgs(argv)
|
||||
cmd.SetIn(&bytes.Buffer{})
|
||||
cmd.SetOut(&bytes.Buffer{})
|
||||
cmd.SetErr(&bytes.Buffer{})
|
||||
|
||||
_, err := cmd.ExecuteC()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
var newTUFErrClient tufClientInstantiator = func(o *tuf.Options) (*tuf.Client, error) {
|
||||
return nil, fmt.Errorf("failed to create TUF client")
|
||||
}
|
||||
|
|
@ -99,3 +185,14 @@ func TestGetTrustedRoot(t *testing.T) {
|
|||
})
|
||||
|
||||
}
|
||||
|
||||
type stubAuthConfig struct {
|
||||
config.AuthConfig
|
||||
hasActiveToken bool
|
||||
}
|
||||
|
||||
var _ gh.AuthConfig = (*stubAuthConfig)(nil)
|
||||
|
||||
func (c *stubAuthConfig) HasActiveToken(host string) bool {
|
||||
return c.hasActiveToken
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
|
|||
Long: heredoc.Docf(`
|
||||
Authenticate with a GitHub host.
|
||||
|
||||
The default hostname is %[1]sgithub.com%[1]s. This can be overridden using the %[1]s--hostname%[1]s
|
||||
flag.
|
||||
|
||||
The default authentication mode is a web-based browser flow. After completion, an
|
||||
authentication token will be stored securely in the system credential store.
|
||||
If a credential store is not found or there is an issue using it gh will fallback
|
||||
|
|
@ -222,21 +225,19 @@ func loginRun(opts *LoginOptions) error {
|
|||
}
|
||||
|
||||
func promptForHostname(opts *LoginOptions) (string, error) {
|
||||
options := []string{"GitHub.com", "GitHub Enterprise Server"}
|
||||
options := []string{"GitHub.com", "Other"}
|
||||
hostType, err := opts.Prompter.Select(
|
||||
"What account do you want to log into?",
|
||||
"Where do you use GitHub?",
|
||||
options[0],
|
||||
options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
isEnterprise := hostType == 1
|
||||
|
||||
hostname := ghinstance.Default()
|
||||
if isEnterprise {
|
||||
hostname, err = opts.Prompter.InputHostname()
|
||||
isGitHubDotCom := hostType == 0
|
||||
if isGitHubDotCom {
|
||||
return ghinstance.Default(), nil
|
||||
}
|
||||
|
||||
return hostname, err
|
||||
return opts.Prompter.InputHostname()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package login
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
|
@ -546,7 +547,7 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
wantErrOut: regexp.MustCompile("Tip: you can generate a Personal Access Token here https://rebecca.chambers/settings/tokens"),
|
||||
},
|
||||
{
|
||||
name: "choose enterprise",
|
||||
name: "choose Other",
|
||||
wantHosts: heredoc.Doc(`
|
||||
brad.vickers:
|
||||
users:
|
||||
|
|
@ -563,8 +564,8 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
switch prompt {
|
||||
case "What account do you want to log into?":
|
||||
return prompter.IndexFor(opts, "GitHub Enterprise Server")
|
||||
case "Where do you use GitHub?":
|
||||
return prompter.IndexFor(opts, "Other")
|
||||
case "What is your preferred protocol for Git operations on this host?":
|
||||
return prompter.IndexFor(opts, "HTTPS")
|
||||
case "How would you like to authenticate GitHub CLI?":
|
||||
|
|
@ -606,7 +607,7 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
switch prompt {
|
||||
case "What account do you want to log into?":
|
||||
case "Where do you use GitHub?":
|
||||
return prompter.IndexFor(opts, "GitHub.com")
|
||||
case "What is your preferred protocol for Git operations on this host?":
|
||||
return prompter.IndexFor(opts, "HTTPS")
|
||||
|
|
@ -640,7 +641,7 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
switch prompt {
|
||||
case "What account do you want to log into?":
|
||||
case "Where do you use GitHub?":
|
||||
return prompter.IndexFor(opts, "GitHub.com")
|
||||
case "What is your preferred protocol for Git operations on this host?":
|
||||
return prompter.IndexFor(opts, "SSH")
|
||||
|
|
@ -803,3 +804,50 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_promptForHostname(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
options []string
|
||||
selectedIndex int
|
||||
// This is so we can test that the options in the function don't change
|
||||
expectedSelection string
|
||||
inputHostname string
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
name: "select 'GitHub.com'",
|
||||
selectedIndex: 0,
|
||||
expectedSelection: "GitHub.com",
|
||||
expect: "github.com",
|
||||
},
|
||||
{
|
||||
name: "select 'Other'",
|
||||
selectedIndex: 1,
|
||||
expectedSelection: "Other",
|
||||
inputHostname: "github.enterprise.com",
|
||||
expect: "github.enterprise.com",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
promptMock := &prompter.PrompterMock{
|
||||
SelectFunc: func(_ string, _ string, options []string) (int, error) {
|
||||
if options[tt.selectedIndex] != tt.expectedSelection {
|
||||
return 0, fmt.Errorf("expected %s at index %d, but got %s", tt.expectedSelection, tt.selectedIndex, options[tt.selectedIndex])
|
||||
}
|
||||
return tt.selectedIndex, nil
|
||||
},
|
||||
InputHostnameFunc: func() (string, error) {
|
||||
return tt.inputHostname, nil
|
||||
},
|
||||
}
|
||||
opts := &LoginOptions{
|
||||
Prompter: promptMock,
|
||||
}
|
||||
hostname, err := promptForHostname(opts)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expect, hostname)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ func NewCmdSetupGit(f *cmdutil.Factory, runF func(*SetupGitOptions) error) *cobr
|
|||
Long: heredoc.Docf(`
|
||||
This command configures %[1]sgit%[1]s to use GitHub CLI as a credential helper.
|
||||
For more information on git credential helpers please reference:
|
||||
https://git-scm.com/docs/gitcredentials.
|
||||
<https://git-scm.com/docs/gitcredentials>.
|
||||
|
||||
By default, GitHub CLI will be set as the credential helper for all authenticated hosts.
|
||||
If there is no authenticated hosts the command fails with an error.
|
||||
|
|
|
|||
|
|
@ -280,9 +280,13 @@ func (m *Manager) installBin(repo ghrepo.Interface, target string) error {
|
|||
}
|
||||
|
||||
if asset == nil {
|
||||
cs := m.io.ColorScheme()
|
||||
errorMessageInRed := fmt.Sprintf(cs.Red("%[1]s unsupported for %[2]s."), repo.RepoName(), platform)
|
||||
issueCreateCommand := generateMissingBinaryIssueCreateCommand(repo.RepoOwner(), repo.RepoName(), platform)
|
||||
|
||||
return fmt.Errorf(
|
||||
"%[1]s unsupported for %[2]s. Open an issue: `gh issue create -R %[3]s/%[1]s -t'Support %[2]s'`",
|
||||
repo.RepoName(), platform, repo.RepoOwner())
|
||||
"%[1]s\n\nTo request support for %[2]s, open an issue on the extension's repo by running the following command:\n\n `%[3]s`",
|
||||
errorMessageInRed, platform, issueCreateCommand)
|
||||
}
|
||||
|
||||
name := repo.RepoName()
|
||||
|
|
@ -334,6 +338,15 @@ func (m *Manager) installBin(repo ghrepo.Interface, target string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func generateMissingBinaryIssueCreateCommand(repoOwner string, repoName string, currentPlatform string) string {
|
||||
issueBody := generateMissingBinaryIssueBody(currentPlatform)
|
||||
return fmt.Sprintf("gh issue create -R %[1]s/%[2]s --title \"Add support for the %[3]s architecture\" --body \"%[4]s\"", repoOwner, repoName, currentPlatform, issueBody)
|
||||
}
|
||||
|
||||
func generateMissingBinaryIssueBody(currentPlatform string) string {
|
||||
return fmt.Sprintf("This extension does not support the %[1]s architecture. I tried to install it on a %[1]s machine, and it failed due to the lack of an available binary. Would you be able to update the extension's build and release process to include the relevant binary? For more details, see <https://docs.github.com/en/github-cli/github-cli/creating-github-cli-extensions>.", currentPlatform)
|
||||
}
|
||||
|
||||
func writeManifest(dir, name string, data []byte) (writeErr error) {
|
||||
path := filepath.Join(dir, name)
|
||||
var f *os.File
|
||||
|
|
|
|||
|
|
@ -906,7 +906,7 @@ func TestManager_Install_binary_unsupported(t *testing.T) {
|
|||
m := newTestManager(tempDir, &client, nil, ios)
|
||||
|
||||
err := m.Install(repo, "")
|
||||
assert.EqualError(t, err, "gh-bin-ext unsupported for windows-amd64. Open an issue: `gh issue create -R owner/gh-bin-ext -t'Support windows-amd64'`")
|
||||
assert.EqualError(t, err, "gh-bin-ext unsupported for windows-amd64.\n\nTo request support for windows-amd64, open an issue on the extension's repo by running the following command:\n\n\t`gh issue create -R owner/gh-bin-ext --title \"Add support for the windows-amd64 architecture\" --body \"This extension does not support the windows-amd64 architecture. I tried to install it on a windows-amd64 machine, and it failed due to the lack of an available binary. Would you be able to update the extension's build and release process to include the relevant binary? For more details, see <https://docs.github.com/en/github-cli/github-cli/creating-github-cli-extensions>.\"`")
|
||||
|
||||
assert.Equal(t, "", stdout.String())
|
||||
assert.Equal(t, "", stderr.String())
|
||||
|
|
|
|||
|
|
@ -93,7 +93,12 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
|
|||
|
||||
To create a remote repository from an existing local repository, specify the source directory with %[1]s--source%[1]s.
|
||||
By default, the remote repository name will be the name of the source directory.
|
||||
|
||||
Pass %[1]s--push%[1]s to push any local commits to the new repository.
|
||||
|
||||
For language or platform .gitignore templates to use with %[1]s--gitignore%[1]s, <https://github.com/github/gitignore>.
|
||||
|
||||
For license keywords to use with %[1]s--license%[1]s, <https://choosealicense.com/>.
|
||||
`, "`"),
|
||||
Example: heredoc.Doc(`
|
||||
# create a repository interactively
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue