Skip to content

feat(file): accept stdin and http(s) URLs as upload sources#31

Merged
4ier merged 1 commit into
mainfrom
feat/file-upload-stdin-url
Apr 30, 2026
Merged

feat(file): accept stdin and http(s) URLs as upload sources#31
4ier merged 1 commit into
mainfrom
feat/file-upload-stdin-url

Conversation

@4ier
Copy link
Copy Markdown
Owner

@4ier 4ier commented Apr 30, 2026

What

Let notion file upload accept three kinds of source:

argument behavior
<path> local file (unchanged)
- read from stdin
http(s)://… HTTP GET, follows redirects

Plus a new --name <filename> flag to override the filename (required for stdin, optional for URLs whose path segment is opaque).

Why

Tracked in #26. Before this PR, uploading anything behind a URL required a manual two-step with curl -o /tmp/... && notion file upload /tmp/... && rm. And stdin wasn't supported at all, so pipelines like gh run view --log | notion file upload - --name run.log were impossible.

Changes

cmd/file.go refactored around a fileSource abstraction. Three loaders funnel into a single uploadFromSource(api, src, targetID) function that performs the existing two-step create + send + (optional) attach flow.

  • loadSourceFromPath — unchanged semantics, preserved for legacy callers (uploadFile back-compat shim still works).
  • loadSourceFromStdin — requires --name; rejects empty stdin up-front.
  • loadSourceFromURL — reads Content-Type, derives filename from Content-Disposition or URL path, strips query/hash, handles non-2xx with a clear error. Scheme + path cuts mean https://x.com/ sensibly falls back to download instead of x.com.

Deliberately out of scope for this PR (the curl-pipe still works for these):

  • custom auth headers for the URL loader,
  • chunked / streaming uploads (Notion's single_part mode, unchanged).

Test plan

  • httptest servers for URL success, Content-Disposition filename extraction, and 404 propagation.
  • os.Pipe stdin redirection for stdin tests.
  • Integration tests prove URL and stdin sources hit the exact same mocked POST /v1/file_uploadsUploadFileContent sequence as a local file.

Closes #26

Previously `notion file upload` only worked with a local filesystem
path. To upload something that lived behind a URL (chat attachment, CI
artifact, object-storage direct link) you had to curl to a tmp file
first. To pipe bytes into Notion you couldn't at all.

This change introduces a fileSource abstraction and three loaders:

  <path>             local file (existing behavior, unchanged)
  -                  read from stdin (requires --name)
  http(s)://...      HTTP GET, follows redirects, reads Content-Type
                     and Content-Disposition filename if present

A new --name flag overrides the filename in all three modes. It is
required for stdin (we can't guess) and recommended for URLs whose
path segment is opaque (e.g. /download?id=123).

Deliberately scoped out of this PR (use a curl-pipe for these):
  - custom auth headers for the URL loader
  - chunked / streaming upload (single-part, same as before)

Tests use httptest for URL loading, os.Pipe to redirect stdin, and
integration tests wire uploadFromAny through the existing fileUploadAPI
mock to prove every source funnels into the same two-step upload flow.

Closes #26
@4ier 4ier force-pushed the feat/file-upload-stdin-url branch from 1be49cd to 8ba87cf Compare April 30, 2026 05:00
@4ier 4ier merged commit b12fca8 into main Apr 30, 2026
4 checks passed
@4ier 4ier deleted the feat/file-upload-stdin-url branch April 30, 2026 05:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

notion file upload: accept http(s) URLs (and/or stdin) as source

1 participant