From 929ee2cc3f7bb9556fc5cc8400d7c8d88a77a75c Mon Sep 17 00:00:00 2001 From: rendylong Date: Thu, 30 Apr 2026 16:18:18 +0800 Subject: [PATCH] fix: preserve filenames for file uploads --- internal/cmdutil/fileupload.go | 11 +++++------ internal/cmdutil/fileupload_test.go | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/internal/cmdutil/fileupload.go b/internal/cmdutil/fileupload.go index 15a99980d..58140ec96 100644 --- a/internal/cmdutil/fileupload.go +++ b/internal/cmdutil/fileupload.go @@ -112,12 +112,11 @@ func BuildFormdata(fileIO fileio.FileIO, fieldName, filePath string, isStdin boo if err != nil { return nil, output.ErrValidation("cannot open file: %s", filePath) } - defer f.Close() - data, err := io.ReadAll(f) - if err != nil { - return nil, output.ErrValidation("--file: failed to read %s: %v", filePath, err) - } - fd.AddFile(fieldName, bytes.NewReader(data)) + // Keep the concrete file reader instead of copying it into a + // bytes.Reader. The Lark SDK preserves multipart filenames only when + // it receives an *os.File; replacing it with an anonymous reader makes + // the SDK fall back to "unknown-file". + fd.AddFile(fieldName, f) } // Add top-level JSON keys as text form fields. diff --git a/internal/cmdutil/fileupload_test.go b/internal/cmdutil/fileupload_test.go index 4e0ab1ca3..8d21607c0 100644 --- a/internal/cmdutil/fileupload_test.go +++ b/internal/cmdutil/fileupload_test.go @@ -7,6 +7,7 @@ import ( "bytes" "os" "path/filepath" + "reflect" "strings" "testing" @@ -276,6 +277,10 @@ func TestBuildFormdata(t *testing.T) { if fd == nil { t.Fatal("expected non-nil Formdata") } + + if got := formdataFieldTypeName(t, fd, "photo"); got != "*os.File" { + t.Fatalf("formdata file field type = %s, want *os.File", got) + } }) t.Run("file not found", func(t *testing.T) { @@ -337,6 +342,23 @@ func TestBuildFormdata(t *testing.T) { }) } +func formdataFieldTypeName(t *testing.T, fd any, field string) string { + t.Helper() + + fields := reflect.ValueOf(fd).Elem().FieldByName("fields") + if !fields.IsValid() { + t.Fatal("Formdata.fields is not available") + } + value := fields.MapIndex(reflect.ValueOf(field)) + if !value.IsValid() { + t.Fatalf("Formdata field %q is missing", field) + } + if value.Kind() == reflect.Interface { + value = value.Elem() + } + return value.Type().String() +} + // TestFormatFormFieldValue locks in the fix for the float64 -> scientific // notation bug. JSON numbers unmarshal to float64, and fmt's default %v for // float64 delegates to %g which switches to scientific notation at ~1e6