Merge remote-tracking branch 'origin/trunk' into prompt-factory

This commit is contained in:
vilmibm 2022-08-15 13:21:22 -05:00
commit 791b8b4173
15 changed files with 76 additions and 46 deletions

View file

@ -253,6 +253,7 @@ func clientOptions(hostname string, transport http.RoundTripper) ghAPI.ClientOpt
Host: hostname,
SkipDefaultHeaders: true,
Transport: transport,
LogIgnoreEnv: true,
}
return opts
}

View file

@ -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
View file

@ -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
View file

@ -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=

View file

@ -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)
}

View file

@ -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

View file

@ -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()

View file

@ -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)"

View file

@ -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",

View file

@ -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

View file

@ -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(

View file

@ -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 {

View file

@ -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)

View file

@ -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()

View file

@ -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