Skip to content

feat: new edge function upload handling#650

Merged
pieh merged 6 commits into
masterfrom
feat/new-edge-function-upload
Jul 7, 2026
Merged

feat: new edge function upload handling#650
pieh merged 6 commits into
masterfrom
feat/new-edge-function-upload

Conversation

@pieh

@pieh pieh commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@netlify

netlify Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploy Preview for open-api ready!

Name Link
🔨 Latest commit 747be7e
🔍 Latest deploy log https://app.netlify.com/projects/open-api/deploys/6a4b8b9ed41665000962d028
😎 Deploy Preview https://deploy-preview-650--open-api.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds support for deploying Edge Functions. The swagger spec gains a new uploadDeployEdgeFunction endpoint and new required_edge_functions/edge_functions schema properties, mirrored in generated Go models. A generated client (parameters, response reader, and Client/ClientService methods) is added for the new endpoint. Porcelain deploy logic adds an edgeFunctionsManifest parser, a bundleEdgeFunctions helper that hashes bundle assets, integrates edge functions into the deploy payload and upload orchestration (uploadFiles/uploadFile), and adjusts the early-exit condition. New tests cover bundling and uploading.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Changes

File(s) Change Summary
go/models/deploy.go, go/models/deploy_files.go Add RequiredEdgeFunctions and EdgeFunctions fields to Deploy/DeployFiles structs
go/plumbing/operations/operations_client.go, upload_deploy_edge_function_parameters.go, upload_deploy_edge_function_responses.go New generated client method, request params, and response types for UploadDeployEdgeFunction
go/porcelain/deploy.go, edge_functions_manifest.go Manifest parsing, bundling, deploy payload wiring, and upload orchestration for edge functions
go/porcelain/deploy_test.go New tests for bundling and uploading edge functions
swagger.yml New endpoint and schema properties for edge function deploys

Sequence Diagram(s)

sequenceDiagram
  participant DoDeploy
  participant bundleEdgeFunctions
  participant uploadFiles
  participant Client
  participant Server
  DoDeploy->>bundleEdgeFunctions: parse manifest.json, hash bundles
  bundleEdgeFunctions-->>DoDeploy: edgeFunctions bundle set
  DoDeploy->>uploadFiles: upload edgeFunctionUpload for RequiredEdgeFunctions
  uploadFiles->>Client: UploadDeployEdgeFunction(deployID, codeSha, fileBody)
  Client->>Server: PUT /deploys/{deploy_id}/edge_functions/{code_sha}
  Server-->>Client: 200 OK or error
Loading

Suggested reviewers: paulo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: adding edge function upload handling.
Description check ✅ Passed The description is related to the changeset and references the linked work it implements.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/new-edge-function-upload

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread go/porcelain/deploy.go

// bundleEdgeFunctions reads the edge-bundler manifest from edgeFunctionsDir and turns each bundle it
// lists into an uploadable FileBundle. The deploy declares these as its edge_functions map
// ({format => code_sha}); the server replies with the subset (required_edge_functions) not already

@pieh pieh Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note - in here we send everything in edge-bundler manifest - including eszip bundles. Bitballoon intentionally only cares about tar ( https://github.com/netlify/bitballoon/blob/ad4d323eb9f9fabf68c5518e4ce701ca9faa964e/app/models/deploy.rb#L1114-L1119 )

Goal of this was to make clients to not to make such decisions and instead have our backed alone decide about what goes through which upload channel.

This way it's much easier for us to control things. It's less relevant for porcelain client which we can rollout with buildbot anytime we want. But the same will be replicated for CLI where impact of this decision is bigger, because we can't fully control over which version is actually used and this should allow us to just eventually turn off tar uploads going through static files uploads channel

@pieh pieh changed the title Feat/new edge function upload feat: new edge function upload handling Jul 6, 2026
@pieh pieh marked this pull request as ready for review July 6, 2026 16:10
@pieh pieh requested review from a team as code owners July 6, 2026 16:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
swagger.yml (1)

1668-1694: 🧹 Nitpick | 🔵 Trivial

Confirm downstream service ownership for this contract.

Per the linked netlify/blueprints docs, edge-function deploy/upload appears to be owned by the Functions Origin service (Nimble/Kraft cloud), not just netlify-server. Given the PR description flags "placeholder assumptions that may change" pending Bitballoon/netlify-server work, worth confirming this exact path/schema shape (/deploys/{deploy_id}/edge_functions/{code_sha}, required_edge_functions/edge_functions) is the agreed contract with whichever service ultimately implements it, to avoid a breaking spec change later.

Also applies to: 4773-4779, 4879-4883

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@swagger.yml` around lines 1668 - 1694, The edge-function upload contract in
the uploadDeployEdgeFunction path should be verified against the downstream
owner before it is finalized, since the current request/response shape may not
match the service that will actually implement it. Confirm that the
/deploys/{deploy_id}/edge_functions/{code_sha} route, the file_body binary body,
and any related required_edge_functions/edge_functions schema expectations are
the agreed API contract with the Functions Origin service; if not, adjust the
Swagger definition and any referenced schemas together to match the
authoritative implementation.

Source: Linked repositories

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@swagger.yml`:
- Around line 1668-1694: The edge-function upload contract in the
uploadDeployEdgeFunction path should be verified against the downstream owner
before it is finalized, since the current request/response shape may not match
the service that will actually implement it. Confirm that the
/deploys/{deploy_id}/edge_functions/{code_sha} route, the file_body binary body,
and any related required_edge_functions/edge_functions schema expectations are
the agreed API contract with the Functions Origin service; if not, adjust the
Swagger definition and any referenced schemas together to match the
authoritative implementation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2bb8278-b9ec-4a55-a3ae-4882f0fca438

📥 Commits

Reviewing files that changed from the base of the PR and between c63de07 and 747be7e.

📒 Files selected for processing (9)
  • go/models/deploy.go
  • go/models/deploy_files.go
  • go/plumbing/operations/operations_client.go
  • go/plumbing/operations/upload_deploy_edge_function_parameters.go
  • go/plumbing/operations/upload_deploy_edge_function_responses.go
  • go/porcelain/deploy.go
  • go/porcelain/deploy_test.go
  • go/porcelain/edge_functions_manifest.go
  • swagger.yml
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • netlify/blueprints (manual)

Comment thread swagger.yml
Comment on lines +1668 to +1694
/deploys/{deploy_id}/edge_functions/{code_sha}:
put:
operationId: uploadDeployEdgeFunction
tags: [edgeFunction]
consumes:
- application/octet-stream
parameters:
- name: deploy_id
type: string
in: path
required: true
- name: code_sha
type: string
in: path
required: true
- name: file_body
in: body
schema:
type: string
format: binary
required: true
- $ref: '#/parameters/retryCount'
responses:
'200':
description: OK
default:
$ref: '#/responses/error'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth doing some extra check here, but here's claude's summary of "correctness" of this:

The endpoint definition is correct — it will interoperate properly with the server. I traced every part of the swagger spec against the handler. Here's the validation:

┌─────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────────┐
│           Swagger (swagger.yml:1668-1694)           │                     Server (request_edge_function_upload.go / server.go)                      │         Match         │
├─────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┤
│ Path /deploys/{deploy_id}/edge_functions/{code_sha} │ Regex ^/api/v1/deploys/(?P<deploy_id>[a-f0-9]+)/edge_functions/(?P<code_sha>[a-f0-9]+)$ (:19) │ ✅                    │
├─────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┤
│ Method put                                          │ Test uses http.MethodPut → 200 (:703-705)                                                     │ ✅ (works)            │
├─────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┤
│ consumes: application/octet-stream                  │ Body streamed raw to UploadEdgeFunctionBundle (:82)                                           │ ✅                    │
├─────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┤
│ file_body binary, required                          │ Reads req body                                                                                │ ✅                    │
├─────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┤
│ retryCount param                                    │ not read by handler                                                                           │ ⚠️ ignored (harmless) │
├─────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────┤
│ Response 200, no schema (empty body)                │ Returns nil → default 200, empty body (:93); test asserts StatusOK                            │ ✅                    │
└─────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────┘

Two minor, non-blocking discrepancies worth knowing

1. Method isn't enforced server-side. The dispatch at server.go:657 matches on URL path only (isFOEdgeFunctionUploadPath(req.URL.Path)), with no method check — unlike the swagger which declares put. So the server would actually accept any verb on that path. This isn't a bug for you: the generated client always issues PUT, so declaring put in swagger is the correct, tighter contract. Just don't expect a GET/POST to that path to be rejected with a 405.

2. retryCount is sent but ignored. Your client sends X-Nf-Retry-Count (params.WithXNfRetryCount), and the swagger declares the retryCount param — but handleFOEdgeFunctionUpload never reads it. So retries work (the client re-PUTs), but the retry-count header has no server-side effect on this endpoint (no metrics/dedup keyed on it). Contrast with the function-upload path, which does thread it through. Not a correctness issue — worth a mental note if you ever expect the server to behave differently on retries.

I did use - $ref: '#/parameters/retryCount' to mimic function uploads - netlify-server similarly doesn't do anything with it - so it's a bit useless, but also seems harmless to have it ... at least it will be consistent with already existing functions definition

@pieh pieh merged commit 223e2de into master Jul 7, 2026
15 checks passed
@pieh pieh deleted the feat/new-edge-function-upload branch July 7, 2026 16:17
pieh pushed a commit that referenced this pull request Jul 7, 2026
🤖 I have created a release *beep* *boop*
---


##
[2.57.0](v2.56.1...v2.57.0)
(2026-07-07)


### Features

* new edge function upload handling
([#650](#650))
([223e2de](223e2de))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: token-generator-app[bot] <82042599+token-generator-app[bot]@users.noreply.github.com>
Co-authored-by: token-generator-app[bot] <token-generator-app[bot]@users.noreply.github.com>
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.

2 participants