mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 19:11:25 +01:00
feat(api): add --verbose to show the request and response headers
--verbose prints the method, URL without query and headers of each request, then the status and headers of its response, on stderr like curl -v. Credentials in Authorization, Proxy-Authorization and Cookie are hidden. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
2 files changed
+53
-9
No files matched your search
+36
-9
@@ -149,7 +149,7 @@ $ tea api -X PATCH repos/alice/project --input settings.json`
|
||||
func (a *application) apiCommand() *cobra.Command {
|
||||
var method, input, output string
|
||||
var raw, typed, headerValues []string
|
||||
var include, paginate, silent bool
|
||||
var include, verbose, paginate, silent bool
|
||||
var maxPages int
|
||||
cmd := &cobra.Command{Use: "api <endpoint>", Short: "Make an authenticated Gitea API request", Long: apiLong, Example: apiExamples, Annotations: map[string]string{"tea.text": "api returns raw responses", "tea.rawjson": "true"}, Args: argsExact(1), RunE: func(cmd *cobra.Command, args []string) error {
|
||||
usage := func(err error) error { return clierr.Wrap(clierr.Usage, err) }
|
||||
@@ -257,8 +257,13 @@ func (a *application) apiCommand() *cobra.Command {
|
||||
response.color = response.tty && a.colorEnabled()
|
||||
}
|
||||
return (services.API{Client: target.client}).Visit(cmd.Context(), services.APIOptions{Endpoint: endpoint, Method: method, Body: body, Headers: headers, Paginate: paginate, MaxPages: maxPages}, func(r *http.Response) error {
|
||||
if include {
|
||||
if err := writeResponseHead(cmd.ErrOrStderr(), r); err != nil {
|
||||
if verbose {
|
||||
if err := writeRequestHead(cmd.ErrOrStderr(), r.Request); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if include || verbose {
|
||||
if err := writeResponseHead(cmd.ErrOrStderr(), r, verbose); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -277,6 +282,7 @@ func (a *application) apiCommand() *cobra.Command {
|
||||
cmd.Flags().StringArrayVarP(&typed, "field", "F", nil, "Add a typed field: `name=value`; @FILE or @- reads a file or stdin")
|
||||
cmd.Flags().StringVar(&output, "output-file", "", "Write the complete response to a new `file`")
|
||||
cmd.Flags().BoolVarP(&include, "include", "i", false, "Print the response status and headers to stderr")
|
||||
cmd.Flags().BoolVar(&verbose, "verbose", false, "Print the request and the response status and headers to stderr")
|
||||
cmd.Flags().BoolVar(&silent, "silent", false, "Do not print the response body")
|
||||
cmd.Flags().BoolVar(&paginate, "paginate", false, "Follow next-page links and print every page")
|
||||
cmd.Flags().IntVar(&maxPages, "max-pages", 1000, "Stop --paginate after this many pages")
|
||||
@@ -337,13 +343,34 @@ func (l *lastByte) Write(p []byte) (int, error) {
|
||||
return l.w.Write(p)
|
||||
}
|
||||
|
||||
// writeResponseHead prints the status line and the sorted headers of r, then a blank line.
|
||||
func writeResponseHead(w io.Writer, r *http.Response) error {
|
||||
// writeResponseHead prints the status line and the sorted headers of r, then a blank line; verbose
|
||||
// marks each line with "< " like curl.
|
||||
func writeResponseHead(w io.Writer, r *http.Response, verbose bool) error {
|
||||
prefix := ""
|
||||
if verbose {
|
||||
prefix = "< "
|
||||
}
|
||||
return writeHead(w, prefix, r.Proto+" "+r.Status, r.Header)
|
||||
}
|
||||
|
||||
// writeRequestHead prints the method, URL without query and headers of r marked with "> ", hiding
|
||||
// credentials.
|
||||
func writeRequestHead(w io.Writer, r *http.Request) error {
|
||||
headers := r.Header.Clone()
|
||||
for _, name := range []string{"Authorization", "Proxy-Authorization", "Cookie"} {
|
||||
if headers.Get(name) != "" {
|
||||
headers.Set(name, "(hidden)")
|
||||
}
|
||||
}
|
||||
return writeHead(w, "> ", r.Method+" "+r.URL.Scheme+"://"+r.URL.Host+r.URL.EscapedPath(), headers)
|
||||
}
|
||||
|
||||
func writeHead(w io.Writer, prefix, first string, headers http.Header) error {
|
||||
var b strings.Builder
|
||||
fmt.Fprintf(&b, "%s %s\n", r.Proto, r.Status)
|
||||
for _, key := range slices.Sorted(maps.Keys(r.Header)) {
|
||||
for _, value := range r.Header.Values(key) {
|
||||
fmt.Fprintf(&b, "%s: %s\n", key, value)
|
||||
b.WriteString(prefix + first + "\n")
|
||||
for _, key := range slices.Sorted(maps.Keys(headers)) {
|
||||
for _, value := range headers.Values(key) {
|
||||
b.WriteString(prefix + terminal.SafeLine(key+": "+value) + "\n")
|
||||
}
|
||||
}
|
||||
b.WriteString("\n")
|
||||
|
||||
Reference in new issue
Block a user