feat: add multipart/form-data support to glab api via --form flag

What does this MR do and why?

Adds a --form flag to glab api that sends the request body as multipart/form-data instead of JSON. This enables file uploads to GitLab REST API endpoints that require a binary file stream, such as wiki attachments.

Previously, --field file=@path would read the file and JSON-encode its contents as a string, which caused a 400 Bad Request from these endpoints.

Usage

glab api --method POST projects/:fullpath/wikis/attachments \
  --form "file=@./image.png" \
  --form "branch=main"

Text fields and file fields can be freely mixed. Use @- to read a file from stdin.

Implementation notes

  • buildMultipartBody in http.go constructs the multipart/form-data body using Go's standard mime/multipart package, following the same pattern used by gitlab.com/gitlab-org/api/client-go/v2's UploadRequest. The client-go method could not be reused directly because it targets retryablehttp.Request and only supports a single fixed-name file field.
  • --form is mutually exclusive with --field, --raw-field, and --input.
  • When --form is used without an explicit --method, the method defaults to POST.
  • The Content-Type: multipart/form-data; boundary=... header is set automatically.

Closes #8229 (closed)

Screenshots or screen recordings

Tested:

./bin/glab api --method POST projects/34675721/wikis/attachments --form "file=@./docs/source/img/glab-logo.png" --form "branch=main"
{
  "file_name": "glab-logo.png",
  "file_path": "uploads/503af223ceed78bdc396d175990214b1/glab-logo.png",
  "branch": "main",
  "link": {
    "url": "uploads/503af223ceed78bdc396d175990214b1/glab-logo.png",
    "markdown": "![glab-logo](uploads/503af223ceed78bdc396d175990214b1/glab-logo.png)"
  }
}

How to set up and validate locally

# Upload a file to a wiki (requires a project with a wiki enabled)
glab api --method POST projects/:fullpath/wikis/attachments \
  --form "file=@./myfile.png" \
  --form "branch=main"

MR acceptance checklist

  • This MR does not break existing behavior
  • Tests added for buildMultipartBody (unit) and flag parsing / mutual exclusions
  • Documentation regenerated via make gen-docs
Edited by Kai Armstrong

Merge request reports

Loading