diff --git a/pkg/cmd/api/api.go b/pkg/cmd/api/api.go index 8273b3635..7427d05b6 100644 --- a/pkg/cmd/api/api.go +++ b/pkg/cmd/api/api.go @@ -37,6 +37,7 @@ type ApiOptions struct { MagicFields []string RawFields []string RequestHeaders []string + Previews []string ShowResponseHeaders bool Paginate bool Silent bool @@ -106,7 +107,10 @@ func NewCmdApi(f *cmdutil.Factory, runF func(*ApiOptions) error) *cobra.Command $ gh api -X GET search/issues -f q='repo:cli/cli is:open remote' # set a custom HTTP header - $ gh api -H 'Accept: application/vnd.github.XYZ-preview+json' ... + $ gh api -H 'Accept: application/vnd.github.v3.raw+json' ... + + # opt into GitHub API previews + $ gh api --preview baptiste,nebula ... # list releases with GraphQL $ gh api graphql -F owner=':owner' -F name=':repo' -f query=' @@ -175,6 +179,7 @@ func NewCmdApi(f *cmdutil.Factory, runF func(*ApiOptions) error) *cobra.Command cmd.Flags().StringArrayVarP(&opts.MagicFields, "field", "F", nil, "Add a typed parameter in `key=value` format") cmd.Flags().StringArrayVarP(&opts.RawFields, "raw-field", "f", nil, "Add a string parameter in `key=value` format") cmd.Flags().StringArrayVarP(&opts.RequestHeaders, "header", "H", nil, "Add a HTTP request header in `key:value` format") + cmd.Flags().StringSliceVarP(&opts.Previews, "preview", "p", nil, "Opt into GitHub API previews") cmd.Flags().BoolVarP(&opts.ShowResponseHeaders, "include", "i", false, "Include HTTP response headers in the output") cmd.Flags().BoolVar(&opts.Paginate, "paginate", false, "Make additional HTTP requests to fetch all pages of results") cmd.Flags().StringVar(&opts.RequestInputFile, "input", "", "The `file` to use as body for the HTTP request") @@ -219,6 +224,10 @@ func apiRun(opts *ApiOptions) error { } } + if len(opts.Previews) > 0 { + requestHeaders = append(requestHeaders, "Accept: "+previewNamesToMIMETypes(opts.Previews)) + } + httpClient, err := opts.HttpClient() if err != nil { return err @@ -513,3 +522,11 @@ func parseErrorResponse(r io.Reader, statusCode int) (io.Reader, string, error) return bodyCopy, "", nil } + +func previewNamesToMIMETypes(names []string) string { + types := []string{fmt.Sprintf("application/vnd.github.%s-preview+json", names[0])} + for _, p := range names[1:] { + types = append(types, fmt.Sprintf("application/vnd.github.%s-preview", p)) + } + return strings.Join(types, ", ") +} diff --git a/pkg/cmd/api/api_test.go b/pkg/cmd/api/api_test.go index 69ffa100d..44582cac8 100644 --- a/pkg/cmd/api/api_test.go +++ b/pkg/cmd/api/api_test.go @@ -910,3 +910,29 @@ func Test_fillPlaceholders(t *testing.T) { }) } } + +func Test_previewNamesToMIMETypes(t *testing.T) { + tests := []struct { + name string + previews []string + want string + }{ + { + name: "single", + previews: []string{"nebula"}, + want: "application/vnd.github.nebula-preview+json", + }, + { + name: "multiple", + previews: []string{"nebula", "baptiste", "squirrel-girl"}, + want: "application/vnd.github.nebula-preview+json, application/vnd.github.baptiste-preview, application/vnd.github.squirrel-girl-preview", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := previewNamesToMIMETypes(tt.previews); got != tt.want { + t.Errorf("previewNamesToMIMETypes() = %q, want %q", got, tt.want) + } + }) + } +}