Skip to content

Commit

Permalink
fix: use bulk update endpoint when deploying multiple slugs
Browse files Browse the repository at this point in the history
  • Loading branch information
sweatybridge committed Feb 11, 2025
1 parent 2ccf148 commit 6aa4622
Show file tree
Hide file tree
Showing 4 changed files with 395 additions and 25 deletions.
132 changes: 129 additions & 3 deletions api/beta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2354,6 +2354,45 @@ paths:
- Edge Functions
security:
- bearer: []
put:
operationId: v1-bulk-update-functions
summary: Bulk update functions
description: >-
Bulk update functions. It will create a new function or replace
existing. The operation is idempotent. NOTE: You will need to manually
bump the version.
parameters:
- name: ref
required: true
in: path
description: Project ref
schema:
minLength: 20
maxLength: 20
type: string
requestBody:
required: true
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/BulkUpdateFunctionBody'
responses:
'200':
description: ''
content:
application/json:
schema:
$ref: '#/components/schemas/BulkUpdateFunctionResponse'
'403':
description: ''
'500':
description: Failed to update functions
tags:
- Edge Functions
security:
- bearer: []
/v1/projects/{ref}/functions/deploy:
post:
operationId: v1-deploy-a-function
Expand All @@ -2376,6 +2415,11 @@ paths:
schema:
pattern: /^[A-Za-z0-9_-]+$/
type: string
- name: bundleOnly
required: false
in: query
schema:
type: boolean
requestBody:
required: true
content:
Expand All @@ -2388,7 +2432,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/FunctionResponse'
$ref: '#/components/schemas/DeployFunctionResponse'
'403':
description: ''
'500':
Expand Down Expand Up @@ -5671,7 +5715,50 @@ components:
- slug
- name
- body
FunctionMetadata:
BulkUpdateFunctionBody:
type: object
properties:
version:
type: integer
created_at:
type: integer
format: int64
id:
type: string
slug:
type: string
name:
type: string
status:
enum:
- ACTIVE
- REMOVED
- THROTTLED
type: string
verify_jwt:
type: boolean
import_map:
type: boolean
entrypoint_path:
type: string
import_map_path:
type: string
required:
- version
- id
- slug
- name
- status
BulkUpdateFunctionResponse:
type: object
properties:
functions:
type: array
items:
$ref: '#/components/schemas/FunctionResponse'
required:
- functions
FunctionDeployMetadata:
type: object
properties:
entrypoint_path:
Expand All @@ -5697,10 +5784,49 @@ components:
type: string
format: binary
metadata:
$ref: '#/components/schemas/FunctionMetadata'
$ref: '#/components/schemas/FunctionDeployMetadata'
required:
- file
- metadata
DeployFunctionResponse:
type: object
properties:
version:
type: integer
created_at:
type: integer
format: int64
updated_at:
type: integer
format: int64
id:
type: string
slug:
type: string
name:
type: string
status:
enum:
- ACTIVE
- REMOVED
- THROTTLED
type: string
verify_jwt:
type: boolean
import_map:
type: boolean
entrypoint_path:
type: string
import_map_path:
type: string
compute_multiplier:
type: number
required:
- version
- id
- slug
- name
- status
FunctionSlugResponse:
type: object
properties:
Expand Down
50 changes: 35 additions & 15 deletions internal/functions/deploy/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@ import (
)

func deploy(ctx context.Context, functionConfig config.FunctionConfig, fsys afero.Fs) error {
bundleOnly := len(functionConfig) > 1
var toUpdate []api.BulkUpdateFunctionBody
for slug, fc := range functionConfig {
if !fc.IsEnabled() {
fmt.Fprintln(os.Stderr, "Skipped deploying Function:", slug)
continue
}
fmt.Fprintln(os.Stderr, "Deploying Function:", slug)
meta := api.FunctionMetadata{
param := api.V1DeployAFunctionParams{Slug: &slug}
if bundleOnly {
param.BundleOnly = &bundleOnly
}
meta := api.FunctionDeployMetadata{
Name: &slug,
EntrypointPath: fc.Entrypoint,
ImportMapPath: &fc.ImportMap,
Expand All @@ -38,14 +44,34 @@ func deploy(ctx context.Context, functionConfig config.FunctionConfig, fsys afer
if len(fc.StaticFiles) > 0 {
meta.StaticPatterns = &fc.StaticFiles
}
if err := upload(ctx, slug, meta, fsys); err != nil {
resp, err := upload(ctx, param, meta, fsys)
if err != nil {
return err
}
toUpdate = append(toUpdate, api.BulkUpdateFunctionBody{
CreatedAt: resp.CreatedAt,
EntrypointPath: resp.EntrypointPath,
Id: resp.Id,
ImportMap: resp.ImportMap,
ImportMapPath: resp.ImportMapPath,
Name: resp.Name,
Slug: resp.Slug,
Status: api.BulkUpdateFunctionBodyStatus(resp.Status),
VerifyJwt: resp.VerifyJwt,
Version: resp.Version,
})
}
if len(toUpdate) > 1 {
if resp, err := utils.GetSupabase().V1BulkUpdateFunctionsWithResponse(ctx, flags.ProjectRef, toUpdate); err != nil {
return errors.Errorf("failed to bulk update: %w", err)
} else if resp.JSON200 == nil {
return errors.Errorf("unexpected bulk update status %d: %s", resp.StatusCode(), string(resp.Body))
}
}
return nil
}

func upload(ctx context.Context, slug string, meta api.FunctionMetadata, fsys afero.Fs) error {
func upload(ctx context.Context, param api.V1DeployAFunctionParams, meta api.FunctionDeployMetadata, fsys afero.Fs) (*api.DeployFunctionResponse, error) {
body, w := io.Pipe()
form := multipart.NewWriter(w)
errchan := make(chan error, 1)
Expand All @@ -57,24 +83,18 @@ func upload(ctx context.Context, slug string, meta api.FunctionMetadata, fsys af
errchan <- err
}
}()
resp, err := utils.GetSupabase().V1DeployAFunctionWithBodyWithResponse(
ctx,
flags.ProjectRef,
&api.V1DeployAFunctionParams{Slug: &slug},
form.FormDataContentType(),
body,
)
resp, err := utils.GetSupabase().V1DeployAFunctionWithBodyWithResponse(ctx, flags.ProjectRef, &param, form.FormDataContentType(), body)
if merr := <-errchan; merr != nil {
return err
return nil, err
} else if err != nil {
return errors.Errorf("failed to deploy function: %w", err)
return nil, errors.Errorf("failed to deploy function: %w", err)
} else if resp.JSON201 == nil {
return errors.Errorf("unexpected deploy status %d: %s", resp.StatusCode(), string(resp.Body))
return nil, errors.Errorf("unexpected deploy status %d: %s", resp.StatusCode(), string(resp.Body))
}
return nil
return resp.JSON201, nil
}

func writeForm(form *multipart.Writer, meta api.FunctionMetadata, fsys afero.Fs) error {
func writeForm(form *multipart.Writer, meta api.FunctionDeployMetadata, fsys afero.Fs) error {
m, err := form.CreateFormField("metadata")
if err != nil {
return errors.Errorf("failed to create metadata: %w", err)
Expand Down
Loading

0 comments on commit 6aa4622

Please sign in to comment.