Skip to content

Commit 98fe669

Browse files
authored
Merge pull request #61 from InsForge/devel
feat: services add --region + insta regions
2 parents fea548e + 432213d commit 98fe669

4 files changed

Lines changed: 26 additions & 2 deletions

File tree

src/commands/regions.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { ApiClient } from '../api.js'
2+
import { info, printJson } from '../util.js'
3+
4+
// insta regions — list the regions a postgres/compute service can be created in.
5+
export async function regionsList(opts: { json?: boolean } = {}): Promise<void> {
6+
const api = await ApiClient.load()
7+
const { regions } = await api.request('GET', '/regions')
8+
if (opts.json) return printJson(regions)
9+
for (const r of regions) info(`${r.slug} ${r.label}`)
10+
}

src/commands/services.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function resolveComputeServiceId(services: Array<{ id: string; type: stri
4545

4646
// ---- commands ----
4747

48-
export type ServicesAddOpts = { branch?: string; public?: boolean; image?: string; port?: string }
48+
export type ServicesAddOpts = { branch?: string; public?: boolean; image?: string; port?: string; region?: string }
4949

5050
// Map service-add options to the platform POST body. Pure, so it's unit-tested without a network
5151
// mock (mirrors deployRequestBody in deploy.ts). Validation (which options are valid for which
@@ -54,12 +54,14 @@ export function servicesAddRequestBody(type: string, name: string, branch: strin
5454
return {
5555
type, name, ...(branch ? { branch } : {}), public: !!opts.public,
5656
...(opts.image ? { image: opts.image } : {}), ...(opts.port ? { port: Number(opts.port) } : {}),
57+
...(opts.region ? { region: opts.region } : {}),
5758
}
5859
}
5960

6061
export async function servicesAdd(type: string, name: string, opts: ServicesAddOpts = {}): Promise<void> {
6162
assertType(type)
6263
if (opts.public && type !== 'storage') throw new Error('--public is only valid for storage services')
64+
if (opts.region && type === 'storage') throw new Error('--region is not valid for storage services')
6365
if (opts.image && type !== 'compute') throw new Error('--image is only valid for compute services')
6466
if (opts.port && type !== 'compute') throw new Error('--port is only valid for compute services')
6567
const api = await ApiClient.load()
@@ -70,7 +72,7 @@ export async function servicesAdd(type: string, name: string, opts: ServicesAddO
7072
const svc = res.body.service
7173
const access = svc.type === 'storage' ? ` [${svc.public ? 'public' : 'private'}]` : ''
7274
const img = svc.image ? ` running ${svc.image}${svc.port ? `:${svc.port}` : ''}` : ''
73-
info(`added ${type} service ${name} on ${branch ?? 'default'} (${svc.id})${access}${img}${svc.domain ? ` — ${svc.domain}` : ''}`)
75+
info(`added ${type} service ${name} on ${branch ?? 'default'} (${svc.id})${access}${svc.region ? ` ${svc.region}` : ''}${img}${svc.domain ? ` — ${svc.domain}` : ''}`)
7476
renderNextActions(res.body.nextActions)
7577
}
7678

src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import * as org from './commands/org.js'
1111
import * as project from './commands/project.js'
1212
import * as branch from './commands/branch.js'
1313
import * as services from './commands/services.js'
14+
import * as regions from './commands/regions.js'
1415
import * as secretsCmd from './commands/secrets.js'
1516
import { deploy } from './commands/deploy.js'
1617
import * as computeCmd from './commands/compute.js'
@@ -104,6 +105,7 @@ br.command('merge <source>').description('Merge a branch service set into anothe
104105
const svc = program.command('services').alias('svc').description('Manage project services (postgres|storage|compute)')
105106
svc.command('add <type> <name>').description('Provision a service on demand (assigns a default domain for postgres/compute)')
106107
.option('--branch <branch>', 'target branch (default: current)')
108+
.option('--region <region>', 'region for postgres/compute, e.g. us-east (see `insta regions`)')
107109
.option('--public', 'storage only: serve the bucket with anonymous public-read (default private)')
108110
.option('--image <url>', 'compute only: run this container image at creation')
109111
.option('--port <n>', 'compute only: port the image listens on (default 8080)')
@@ -161,6 +163,9 @@ compute.command('status [service]').description("Show a compute service's desire
161163
// ---- manifest ----
162164
program.command('manifest').description('Print an agent-legible view of the project environments').option('--json').action(guard((o) => manifest(o)))
163165

166+
// ---- regions ----
167+
program.command('regions').description('List regions available for postgres/compute services').option('--json').action(guard((o) => regions.regionsList(o)))
168+
164169
// ---- observability ----
165170
program.command('metrics <target> [group]').description('Service metrics (target: db|compute)')
166171
.option('--branch <b>').option('--from <unix>').option('--to <unix>').option('--step <s>').option('--json')

test/services.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ describe('servicesAddRequestBody', () => {
9595
it('carries --public through unchanged', () => {
9696
expect(servicesAddRequestBody('storage', 'bkt', 'main', { public: true })).toMatchObject({ public: true })
9797
})
98+
it('sends region when passed, omits it when absent', () => {
99+
expect(servicesAddRequestBody('postgres', 'db', 'main', { region: 'us-east' })).toMatchObject({ region: 'us-east' })
100+
expect(servicesAddRequestBody('postgres', 'db', 'main', {})).not.toHaveProperty('region')
101+
})
98102
})
99103

100104
describe('servicesAdd validation (throws before any network/config access)', () => {
@@ -107,6 +111,9 @@ describe('servicesAdd validation (throws before any network/config access)', ()
107111
it('rejects --public for a non-storage type', async () => {
108112
await expect(servicesAdd('compute', 'api', { public: true })).rejects.toThrow(/--public is only valid for storage services/)
109113
})
114+
it('rejects --region for a storage type', async () => {
115+
await expect(servicesAdd('storage', 'bkt', { region: 'us-east' })).rejects.toThrow(/--region is not valid for storage services/)
116+
})
110117
it('rejects an unknown service type before any option checks', async () => {
111118
await expect(servicesAdd('lambda', 'x', {})).rejects.toThrow(/postgres\|storage\|compute/)
112119
})

0 commit comments

Comments
 (0)