Merge remote-tracking branch 'origin/trunk' into prompt-factory
This commit is contained in:
commit
791b8b4173
15 changed files with 76 additions and 46 deletions
|
|
@ -253,6 +253,7 @@ func clientOptions(hostname string, transport http.RoundTripper) ghAPI.ClientOpt
|
|||
Host: hostname,
|
||||
SkipDefaultHeaders: true,
|
||||
Transport: transport,
|
||||
LogIgnoreEnv: true,
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
|
|
@ -22,16 +23,23 @@ type HTTPClientOptions struct {
|
|||
Config tokenGetter
|
||||
EnableCache bool
|
||||
Log io.Writer
|
||||
LogColorize bool
|
||||
SkipAcceptHeaders bool
|
||||
}
|
||||
|
||||
func NewHTTPClient(opts HTTPClientOptions) (*http.Client, error) {
|
||||
// Provide invalid host, and token values so gh.HTTPClient will not automatically resolve them.
|
||||
// The real host and token are inserted at request time.
|
||||
clientOpts := ghAPI.ClientOptions{Host: "none", AuthToken: "none"}
|
||||
clientOpts := ghAPI.ClientOptions{
|
||||
Host: "none",
|
||||
AuthToken: "none",
|
||||
LogIgnoreEnv: true,
|
||||
}
|
||||
|
||||
if debugEnabled, _ := utils.IsDebugEnabled(); debugEnabled {
|
||||
if debugEnabled, debugValue := utils.IsDebugEnabled(); debugEnabled {
|
||||
clientOpts.Log = opts.Log
|
||||
clientOpts.LogColorize = opts.LogColorize
|
||||
clientOpts.LogVerboseHTTP = strings.Contains(debugValue, "api")
|
||||
}
|
||||
|
||||
headers := map[string]string{
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -9,7 +9,7 @@ require (
|
|||
github.com/charmbracelet/glamour v0.4.0
|
||||
github.com/charmbracelet/lipgloss v0.5.0
|
||||
github.com/cli/browser v1.1.0
|
||||
github.com/cli/go-gh v0.0.4-0.20220725193052-79f89db738dc
|
||||
github.com/cli/go-gh v0.1.0
|
||||
github.com/cli/oauth v0.9.0
|
||||
github.com/cli/safeexec v1.0.0
|
||||
github.com/cli/shurcooL-graphql v0.0.1
|
||||
|
|
|
|||
7
go.sum
7
go.sum
|
|
@ -58,8 +58,8 @@ github.com/cli/browser v1.1.0 h1:xOZBfkfY9L9vMBgqb1YwRirGu6QFaQ5dP/vXt5ENSOY=
|
|||
github.com/cli/browser v1.1.0/go.mod h1:HKMQAt9t12kov91Mn7RfZxyJQQgWgyS/3SZswlZ5iTI=
|
||||
github.com/cli/crypto v0.0.0-20210929142629-6be313f59b03 h1:3f4uHLfWx4/WlnMPXGai03eoWAI+oGHJwr+5OXfxCr8=
|
||||
github.com/cli/crypto v0.0.0-20210929142629-6be313f59b03/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
github.com/cli/go-gh v0.0.4-0.20220725193052-79f89db738dc h1:qHm0KQPwmr2gsov+Vqsb0bm5jwWykf8zfUS0Q0/xeR4=
|
||||
github.com/cli/go-gh v0.0.4-0.20220725193052-79f89db738dc/go.mod h1:YDzUlo0eCH9G0jY2CONIPYSuIMiQiSDnWaTB/YW6yfk=
|
||||
github.com/cli/go-gh v0.1.0 h1:kMqFmC3ECBrV2UKzlOHjNOTTchExVc5tjNHtCqk/zYk=
|
||||
github.com/cli/go-gh v0.1.0/go.mod h1:eTGWl99EMZ+3Iau5C6dHyGAJRRia65MtdBtuhWc+84o=
|
||||
github.com/cli/oauth v0.9.0 h1:nxBC0Df4tUzMkqffAB+uZvisOwT3/N9FpkfdTDtafxc=
|
||||
github.com/cli/oauth v0.9.0/go.mod h1:qd/FX8ZBD6n1sVNQO3aIdRxeu5LGw9WhKnYhIIoC2A4=
|
||||
github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
|
||||
|
|
@ -150,7 +150,6 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
|||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
|
|
@ -209,7 +208,6 @@ github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0 h1:STjmj0uFfRryL
|
|||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||
github.com/muhammadmuzzammil1998/jsonc v0.0.0-20201229145248-615b0916ca38 h1:0FrBxrkJ0hVembTb/e4EU5Ml6vLcOusAqymmYISg5Uo=
|
||||
github.com/muhammadmuzzammil1998/jsonc v0.0.0-20201229145248-615b0916ca38/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
|
|
@ -515,7 +513,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
|
|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
|
||||
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ func authFlow(oauthHost string, IO *iostreams.IOStreams, notice string, addition
|
|||
return "", "", err
|
||||
}
|
||||
|
||||
userLogin, err := getViewer(oauthHost, token.Token)
|
||||
userLogin, err := getViewer(oauthHost, token.Token, IO.ErrOut)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
|
@ -145,8 +145,11 @@ func (c cfg) AuthToken(hostname string) (string, string) {
|
|||
return c.authToken, "oauth_token"
|
||||
}
|
||||
|
||||
func getViewer(hostname, token string) (string, error) {
|
||||
opts := api.HTTPClientOptions{Config: cfg{authToken: token}}
|
||||
func getViewer(hostname, token string, logWriter io.Writer) (string, error) {
|
||||
opts := api.HTTPClientOptions{
|
||||
Config: cfg{authToken: token},
|
||||
Log: logWriter,
|
||||
}
|
||||
client, err := api.NewHTTPClient(opts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -180,5 +183,7 @@ func verboseLog(out io.Writer, logTraffic bool, colorize bool) func(http.RoundTr
|
|||
}
|
||||
|
||||
func inspectableMIMEType(t string) bool {
|
||||
return strings.HasPrefix(t, "text/") || jsonTypeRE.MatchString(t)
|
||||
return strings.HasPrefix(t, "text/") ||
|
||||
strings.HasPrefix(t, "application/x-www-form-urlencoded") ||
|
||||
jsonTypeRE.MatchString(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,10 +272,7 @@ func apiRun(opts *ApiOptions) error {
|
|||
httpClient = api.NewCachedHTTPClient(httpClient, opts.CacheTTL)
|
||||
}
|
||||
|
||||
headersOutputStream := opts.IO.Out
|
||||
if opts.Silent {
|
||||
opts.IO.Out = io.Discard
|
||||
} else {
|
||||
if !opts.Silent {
|
||||
if err := opts.IO.StartPager(); err == nil {
|
||||
defer opts.IO.StopPager()
|
||||
} else {
|
||||
|
|
@ -283,6 +280,12 @@ func apiRun(opts *ApiOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
bodyWriter := opts.IO.Out
|
||||
headersWriter := opts.IO.Out
|
||||
if opts.Silent {
|
||||
bodyWriter = io.Discard
|
||||
}
|
||||
|
||||
cfg, err := opts.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -303,7 +306,7 @@ func apiRun(opts *ApiOptions) error {
|
|||
return err
|
||||
}
|
||||
|
||||
endCursor, err := processResponse(resp, opts, headersOutputStream, &template)
|
||||
endCursor, err := processResponse(resp, opts, bodyWriter, headersWriter, &template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -330,11 +333,11 @@ func apiRun(opts *ApiOptions) error {
|
|||
return template.End()
|
||||
}
|
||||
|
||||
func processResponse(resp *http.Response, opts *ApiOptions, headersOutputStream io.Writer, template *export.Template) (endCursor string, err error) {
|
||||
func processResponse(resp *http.Response, opts *ApiOptions, bodyWriter, headersWriter io.Writer, template *export.Template) (endCursor string, err error) {
|
||||
if opts.ShowResponseHeaders {
|
||||
fmt.Fprintln(headersOutputStream, resp.Proto, resp.Status)
|
||||
printHeaders(headersOutputStream, resp.Header, opts.IO.ColorEnabled())
|
||||
fmt.Fprint(headersOutputStream, "\r\n")
|
||||
fmt.Fprintln(headersWriter, resp.Proto, resp.Status)
|
||||
printHeaders(headersWriter, resp.Header, opts.IO.ColorEnabled())
|
||||
fmt.Fprint(headersWriter, "\r\n")
|
||||
}
|
||||
|
||||
if resp.StatusCode == 204 {
|
||||
|
|
@ -362,20 +365,20 @@ func processResponse(resp *http.Response, opts *ApiOptions, headersOutputStream
|
|||
|
||||
if opts.FilterOutput != "" && serverError == "" {
|
||||
// TODO: reuse parsed query across pagination invocations
|
||||
err = export.FilterJSON(opts.IO.Out, responseBody, opts.FilterOutput)
|
||||
err = export.FilterJSON(bodyWriter, responseBody, opts.FilterOutput)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else if opts.Template != "" && serverError == "" {
|
||||
// TODO: reuse parsed template across pagination invocations
|
||||
err = template.Execute(responseBody)
|
||||
err = template.Execute(bodyWriter, responseBody)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else if isJSON && opts.IO.ColorEnabled() {
|
||||
err = jsoncolor.Write(opts.IO.Out, responseBody, " ")
|
||||
err = jsoncolor.Write(bodyWriter, responseBody, " ")
|
||||
} else {
|
||||
_, err = io.Copy(opts.IO.Out, responseBody)
|
||||
_, err = io.Copy(bodyWriter, responseBody)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1299,7 +1299,7 @@ func Test_processResponse_template(t *testing.T) {
|
|||
Template: `{{range .}}{{.title}} ({{.labels | pluck "name" | join ", " }}){{"\n"}}{{end}}`,
|
||||
}
|
||||
template := export.NewTemplate(ios, opts.Template)
|
||||
_, err := processResponse(&resp, &opts, io.Discard, &template)
|
||||
_, err := processResponse(&resp, &opts, ios.Out, io.Discard, &template)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = template.End()
|
||||
|
|
|
|||
|
|
@ -488,10 +488,9 @@ func getRepoSuggestions(ctx context.Context, apiClient apiClient, partialSearch
|
|||
|
||||
// buildDisplayName returns display name to be used in the machine survey prompt.
|
||||
// prebuildAvailability will be migrated to use enum values: "none", "ready", "in_progress" before Prebuild GA
|
||||
// Enum values "blob" and "pool" will be deprecated soon.
|
||||
func buildDisplayName(displayName string, prebuildAvailability string) string {
|
||||
switch prebuildAvailability {
|
||||
case "blob", "pool", "ready":
|
||||
case "ready":
|
||||
return displayName + " (Prebuild ready)"
|
||||
case "in_progress":
|
||||
return displayName + " (Prebuild in progress)"
|
||||
|
|
|
|||
|
|
@ -490,16 +490,6 @@ func TestBuildDisplayName(t *testing.T) {
|
|||
prebuildAvailability string
|
||||
expectedDisplayName string
|
||||
}{
|
||||
{
|
||||
name: "prebuild availability is pool",
|
||||
prebuildAvailability: "pool",
|
||||
expectedDisplayName: "4 cores, 8 GB RAM, 32 GB storage (Prebuild ready)",
|
||||
},
|
||||
{
|
||||
name: "prebuild availability is blob",
|
||||
prebuildAvailability: "blob",
|
||||
expectedDisplayName: "4 cores, 8 GB RAM, 32 GB storage (Prebuild ready)",
|
||||
},
|
||||
{
|
||||
name: "prebuild availability is none",
|
||||
prebuildAvailability: "none",
|
||||
|
|
|
|||
|
|
@ -63,6 +63,15 @@ func newSSHCmd(app *App) *cobra.Command {
|
|||
|
||||
Once that is set up (see the second example below), you can ssh to codespaces as
|
||||
if they were ordinary remote hosts (using 'ssh', not 'gh cs ssh').
|
||||
|
||||
Note that the codespace you are connecting to must have an SSH server pre-installed.
|
||||
If the docker image being used for the codespace does not have an SSH server,
|
||||
install it in your Dockerfile or you can try adding the following snippet
|
||||
in your devcontainer.json:
|
||||
|
||||
"features": {
|
||||
"sshd": "latest"
|
||||
}
|
||||
`),
|
||||
Example: heredoc.Doc(`
|
||||
$ gh codespace ssh
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
|
|||
|
||||
See the list of available extensions at <https://github.com/topics/gh-extension>.
|
||||
`, "`"),
|
||||
Aliases: []string{"extensions"},
|
||||
Aliases: []string{"extensions", "ext"},
|
||||
}
|
||||
|
||||
extCmd.AddCommand(
|
||||
|
|
|
|||
|
|
@ -91,9 +91,10 @@ func httpClientFunc(f *cmdutil.Factory, appVersion string) func() (*http.Client,
|
|||
return nil, err
|
||||
}
|
||||
opts := api.HTTPClientOptions{
|
||||
Config: cfg,
|
||||
Log: io.ErrOut,
|
||||
AppVersion: appVersion,
|
||||
Config: cfg,
|
||||
Log: io.ErrOut,
|
||||
LogColorize: io.ColorEnabled(),
|
||||
AppVersion: appVersion,
|
||||
}
|
||||
client, err := api.NewHTTPClient(opts)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ func bareHTTPClient(f *cmdutil.Factory, version string) func() (*http.Client, er
|
|||
AppVersion: version,
|
||||
Config: cfg,
|
||||
Log: f.IOStreams.ErrOut,
|
||||
LogColorize: f.IOStreams.ColorEnabled(),
|
||||
SkipAcceptHeaders: true,
|
||||
}
|
||||
return api.NewHTTPClient(opts)
|
||||
|
|
|
|||
|
|
@ -76,9 +76,7 @@ func (t *Template) parseTemplate(tpl string) (*template.Template, error) {
|
|||
return template.New("").Funcs(templateFuncs).Parse(tpl)
|
||||
}
|
||||
|
||||
func (t *Template) Execute(input io.Reader) error {
|
||||
w := t.io.Out
|
||||
|
||||
func (t *Template) Execute(w io.Writer, input io.Reader) error {
|
||||
if t.template == nil {
|
||||
template, err := t.parseTemplate(t.templateStr)
|
||||
if err != nil {
|
||||
|
|
@ -103,7 +101,7 @@ func (t *Template) Execute(input io.Reader) error {
|
|||
|
||||
func ExecuteTemplate(io *iostreams.IOStreams, input io.Reader, template string) error {
|
||||
t := NewTemplate(io, template)
|
||||
if err := t.Execute(input); err != nil {
|
||||
if err := t.Execute(io.Out, input); err != nil {
|
||||
return err
|
||||
}
|
||||
return t.End()
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -46,6 +47,7 @@ type IOStreams struct {
|
|||
|
||||
alternateScreenBufferEnabled bool
|
||||
alternateScreenBufferActive bool
|
||||
alternateScreenBufferMu sync.Mutex
|
||||
|
||||
stdinTTYOverride bool
|
||||
stdinIsTTY bool
|
||||
|
|
@ -283,13 +285,29 @@ func (s *IOStreams) StopProgressIndicator() {
|
|||
|
||||
func (s *IOStreams) StartAlternateScreenBuffer() {
|
||||
if s.alternateScreenBufferEnabled {
|
||||
s.alternateScreenBufferMu.Lock()
|
||||
defer s.alternateScreenBufferMu.Unlock()
|
||||
|
||||
if _, err := fmt.Fprint(s.Out, "\x1b[?1049h"); err == nil {
|
||||
s.alternateScreenBufferActive = true
|
||||
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, os.Interrupt)
|
||||
|
||||
go func() {
|
||||
<-ch
|
||||
s.StopAlternateScreenBuffer()
|
||||
|
||||
os.Exit(1)
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IOStreams) StopAlternateScreenBuffer() {
|
||||
s.alternateScreenBufferMu.Lock()
|
||||
defer s.alternateScreenBufferMu.Unlock()
|
||||
|
||||
if s.alternateScreenBufferActive {
|
||||
fmt.Fprint(s.Out, "\x1b[?1049l")
|
||||
s.alternateScreenBufferActive = false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue