Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/commands/blobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ netlify blobs:set my-store my-key --input ./some-file.txt
netlify blobs:delete my-store my-key
netlify blobs:list my-store
netlify blobs:list my-store --json
netlify blobs:list my-store --region eu-central-1
```

---
Expand All @@ -61,6 +62,7 @@ netlify blobs:delete

- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
- `force` (*boolean*) - Bypasses prompts & Force the command to run.
- `region` (*string*) - The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used
- `debug` (*boolean*) - Print debugging information
- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in

Expand All @@ -84,6 +86,7 @@ netlify blobs:get

- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
- `output` (*string*) - Defines the filesystem path where the blob data should be persisted
- `region` (*string*) - The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used
- `debug` (*boolean*) - Print debugging information
- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in

Expand All @@ -110,6 +113,7 @@ netlify blobs:list
- `prefix` (*string*) - A string for filtering down the entries; when specified, only the entries whose key starts with that prefix are returned
- `debug` (*boolean*) - Print debugging information
- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in
- `region` (*string*) - The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used

---
## `blobs:set`
Expand All @@ -133,6 +137,7 @@ netlify blobs:set
- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
- `force` (*boolean*) - Bypasses prompts & Force the command to run.
- `input` (*string*) - Defines the filesystem path where the blob data should be read from
- `region` (*string*) - The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used
- `debug` (*boolean*) - Print debugging information
- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in

Expand Down
3 changes: 2 additions & 1 deletion src/commands/blobs/blobs-delete.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getStore } from '@netlify/blobs'
import { getStore, type GetStoreOptions } from '@netlify/blobs'

import { chalk, logAndThrowError, log } from '../../utils/command-helpers.js'
import { promptBlobDelete } from '../../utils/prompts/blob-delete-prompts.js'
Expand All @@ -13,6 +13,7 @@ export const blobsDelete = async (storeName: string, key: string, _options: Reco
const store = getStore({
apiURL: `${api.scheme}://${api.host}`,
name: storeName,
region: _options.region as GetStoreOptions['region'],
siteID: siteInfo.id ?? '',
token: api.accessToken ?? '',
})
Expand Down
4 changes: 3 additions & 1 deletion src/commands/blobs/blobs-get.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { promises as fs } from 'fs'
import { resolve } from 'path'

import { getStore } from '@netlify/blobs'
import { getStore, type GetStoreOptions } from '@netlify/blobs'
import { OptionValues } from 'commander'

import { chalk, logAndThrowError } from '../../utils/command-helpers.js'
import BaseCommand from '../base-command.js'

interface Options extends OptionValues {
output?: string
region?: GetStoreOptions['region']
}

export const blobsGet = async (storeName: string, key: string, options: Options, command: BaseCommand) => {
Expand All @@ -17,6 +18,7 @@ export const blobsGet = async (storeName: string, key: string, options: Options,
const store = getStore({
apiURL: `${api.scheme}://${api.host}`,
name: storeName,
region: options.region,
siteID: siteInfo?.id ?? '',
token: api.accessToken ?? '',
})
Expand Down
4 changes: 3 additions & 1 deletion src/commands/blobs/blobs-list.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getStore } from '@netlify/blobs'
import { getStore, type GetStoreOptions } from '@netlify/blobs'
import AsciiTable from 'ascii-table'
import { OptionValues } from 'commander'

Expand All @@ -9,13 +9,15 @@ interface Options extends OptionValues {
directories?: boolean
json?: boolean
prefix?: string
region?: GetStoreOptions['region']
}

export const blobsList = async (storeName: string, options: Options, command: BaseCommand) => {
const { api, siteInfo } = command.netlify
const store = getStore({
apiURL: `${api.scheme}://${api.host}`,
name: storeName,
region: options.region,
siteID: siteInfo.id,
token: api.accessToken ?? '',
})
Expand Down
4 changes: 3 additions & 1 deletion src/commands/blobs/blobs-set.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { promises as fs } from 'fs'
import { resolve } from 'path'

import { getStore } from '@netlify/blobs'
import { getStore, type GetStoreOptions } from '@netlify/blobs'
import { OptionValues } from 'commander'

import { chalk, logAndThrowError, isNodeError, log } from '../../utils/command-helpers.js'
Expand All @@ -11,6 +11,7 @@ import BaseCommand from '../base-command.js'
interface Options extends OptionValues {
input?: string
force?: string | boolean
region?: GetStoreOptions['region']
}

export const blobsSet = async (
Expand All @@ -25,6 +26,7 @@ export const blobsSet = async (
const store = getStore({
apiURL: `${api.scheme}://${api.host}`,
name: storeName,
region: options.region,
siteID: siteInfo.id,
token: api.accessToken ?? '',
})
Expand Down
17 changes: 17 additions & 0 deletions src/commands/blobs/blobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export const createBlobsCommand = (program: BaseCommand) => {
.description(`Deletes an object with a given key, if it exists, from a Netlify Blobs store`)
.argument('<store>', 'Name of the store')
.argument('<key>', 'Object key')
.option(
'--region <region>',
"The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used",
)
.alias('blob:delete')
.hook('preAction', requiresSiteInfo)
.action(async (storeName: string, key: string, _options: OptionValues, command: BaseCommand) => {
Expand All @@ -35,6 +39,10 @@ export const createBlobsCommand = (program: BaseCommand) => {
.argument('<store>', 'Name of the store')
.argument('<key>', 'Object key')
.option('-O, --output <path>', 'Defines the filesystem path where the blob data should be persisted')
.option(
'--region <region>',
"The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used",
)
.alias('blob:get')
.hook('preAction', requiresSiteInfo)
.action(async (storeName: string, key: string, options: OptionValues, command: BaseCommand) => {
Expand All @@ -55,6 +63,10 @@ export const createBlobsCommand = (program: BaseCommand) => {
`A string for filtering down the entries; when specified, only the entries whose key starts with that prefix are returned`,
)
.option('--json', 'Output list contents as JSON')
.option(
'--region <region>',
"The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used",
)
.alias('blob:list')
.hook('preAction', requiresSiteInfo)
.action(async (storeName: string, options: OptionValues, command: BaseCommand) => {
Expand All @@ -71,6 +83,10 @@ export const createBlobsCommand = (program: BaseCommand) => {
.argument('<key>', 'Object key')
.argument('[value...]', 'Object value')
.option('-i, --input <path>', 'Defines the filesystem path where the blob data should be read from')
.option(
'--region <region>',
"The region where the store data is held, such as 'eu-central-1'; when omitted, the default region is used",
)
.alias('blob:set')
.hook('preAction', requiresSiteInfo)

Expand Down Expand Up @@ -98,6 +114,7 @@ For more information about Netlify Blobs, see ${terminalLink(docsUrl, docsUrl, {
'netlify blobs:delete my-store my-key',
'netlify blobs:list my-store',
'netlify blobs:list my-store --json',
'netlify blobs:list my-store --region eu-central-1',
])
.action(blobs)
}
33 changes: 33 additions & 0 deletions tests/integration/commands/blobs/blobs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('blobs:* commands', () => {
const directory = temporaryDirectory()

let server: BlobsServer
const requestedURLs: string[] = []
const routes: Route[] = [
{ path: 'sites/site_id', response: siteInfo },

Expand All @@ -50,6 +51,7 @@ describe('blobs:* commands', () => {
method: 'all',
path: 'blobs/{*splat}',
response: (req, res) => {
requestedURLs.push(req.url)
blobsProxy.web(req, res, { target: `http://localhost:${address.port}` })
},
})
Expand Down Expand Up @@ -118,5 +120,36 @@ describe('blobs:* commands', () => {
}),
).rejects.toThrowError('Error: Blob my-key does not exist in store my-store')
})

test<FixtureTestContext>('should send the region to the API when one is given', async ({ fixture }) => {
const region = 'eu-central-1'

requestedURLs.length = 0
await fixture.callCli(['blobs:list', 'my-store', '--region', region, '--json'], {
offline: false,
parseJson: true,
})

expect(requestedURLs.some((url) => url.includes(`region=${region}`))).toBe(true)
})

test<FixtureTestContext>('should not send a region when none is given', async ({ fixture }) => {
requestedURLs.length = 0
await fixture.callCli(['blobs:list', 'my-store', '--json'], {
offline: false,
parseJson: true,
})

expect(requestedURLs.length).toBeGreaterThan(0)
expect(requestedURLs.some((url) => url.includes('region'))).toBe(false)
})

test<FixtureTestContext>('should reject a region the Blobs client does not support', async ({ fixture }) => {
await expect(
fixture.callCli(['blobs:list', 'my-store', '--region', 'mars-north-1', '--json'], {
offline: false,
}),
).rejects.toThrowError('not a supported Netlify Blobs region')
})
})
})
Loading