-
Notifications
You must be signed in to change notification settings - Fork 1
feat(compute): add mount path and startup command controls #264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,8 @@ vi.mock('../src/api.js', async (original) => ({ | |
| requireProject: async () => ({ projectId: 'p1', branch: 'main' }), | ||
| })) | ||
| vi.mock('../src/util.js', async (original) => ({ ...await original<typeof import('../src/util.js')>(), info: vi.fn(), printJson: vi.fn() })) | ||
| import { computeVolume } from '../src/commands/compute.js' | ||
| import { info, printJson } from '../src/util.js' | ||
| import { computeVolume, computeStartCommand } from '../src/commands/compute.js' | ||
| import { servicesAdd, serviceAddedLine, serviceListLine } from '../src/commands/services.js' | ||
| beforeEach(() => { | ||
| fake.request.mockReset(); fake.rawRequest.mockReset(); fake.load.mockReset().mockResolvedValue(fake) | ||
|
|
@@ -35,11 +36,10 @@ describe('volume mount path requests', () => { | |
| }) | ||
|
|
||
| describe('mount path validation and list display', () => { | ||
| it.each([undefined, ''])('rejects mount path with missing or empty size (%j) before loading configuration', async (size) => { | ||
| await expect(computeVolume('web', { size, mountPath: '/cache' })).rejects.toThrow('--mount-path requires --size') | ||
| expect(fake.load).not.toHaveBeenCalled() | ||
| expect(fake.request).not.toHaveBeenCalled() | ||
| expect(fake.rawRequest).not.toHaveBeenCalled() | ||
| it('sends a path-only edit without an implicit resize', async () => { | ||
| fake.request.mockResolvedValueOnce({ services: [{ id: 's1', type: 'compute', name: 'web' }] }).mockResolvedValueOnce({ volume: { sizeGib: 1, mountPath: '/data' } }) | ||
| await computeVolume('web', { mountPath: '/cache' }) | ||
| expect(fake.rawRequest).toHaveBeenCalledWith('PUT', '/projects/p1/services/s1/volume', { mountPath: '/cache', sizeGib: undefined }) | ||
| }) | ||
| it.each(['/app/storage', '/data', null, undefined])('shows the recorded compute volume path (%j), defaulting legacy rows to /data', (path) => { | ||
| const line = serviceListLine({ type: 'compute', name: 'web', status: 'active', id: 's1', machine_count: 1, volume_gib: 1, volume_mount_path: path }) | ||
|
|
@@ -51,3 +51,42 @@ describe('mount path validation and list display', () => { | |
| expect(line).not.toContain('/cache') | ||
| }) | ||
| }) | ||
|
|
||
| describe('startup command staging', () => { | ||
| it('saves a command without deploying and honors branch selection', async () => { | ||
| await computeStartCommand('web', { set: 'exec postgres -D /new/pg', branch: 'preview' }) | ||
| expect(fake.request).toHaveBeenCalledWith('GET', '/projects/p1/services?branch=preview') | ||
| expect(fake.rawRequest).toHaveBeenCalledTimes(1) | ||
| expect(fake.rawRequest).toHaveBeenCalledWith('PATCH', '/projects/p1/services/s1', { startCommand: 'exec postgres -D /new/pg' }) | ||
| }) | ||
| it('clears to the image default', async () => { | ||
| await computeStartCommand('web', { clear: true }) | ||
| expect(fake.rawRequest).toHaveBeenCalledWith('PATCH', '/projects/p1/services/s1', { startCommand: '' }) | ||
| }) | ||
| it('reads without mutation and rejects conflicting options before loading credentials', async () => { | ||
| await computeStartCommand('web', {}) | ||
| expect(fake.rawRequest).not.toHaveBeenCalled() | ||
| fake.load.mockClear() | ||
| await expect(computeStartCommand('web', { set: 'x', clear: true })).rejects.toThrow('not both') | ||
| expect(fake.load).not.toHaveBeenCalled() | ||
| }) | ||
| }) | ||
|
|
||
| it('rejects path-only attachment before issuing a write', async () => { | ||
| fake.request.mockResolvedValueOnce({ services: [{ id: 's1', type: 'compute', name: 'web' }] }).mockResolvedValueOnce({ volume: null }) | ||
| await expect(computeVolume('web', { mountPath: '/cache' })).rejects.toThrow('no volume attached') | ||
| expect(fake.rawRequest).not.toHaveBeenCalled() | ||
| }) | ||
| it('rejects an explicitly empty size', async () => { | ||
| await expect(computeVolume('web', { size: '', mountPath: '/cache' })).rejects.toThrow('--size must not be empty') | ||
| expect(fake.load).not.toHaveBeenCalled() | ||
| }) | ||
|
|
||
| it('reads the saved startup command in text and JSON', async () => { | ||
| const service = { id: 's1', type: 'compute', name: 'web', start_command: 'exec app' } | ||
| fake.request.mockResolvedValue({ services: [service] }) | ||
| await computeStartCommand('web', {}) | ||
| expect(info).toHaveBeenCalledWith('compute web: startup command exec app') | ||
| await computeStartCommand('web', { json: true }) | ||
| expect(printJson).toHaveBeenCalledWith({ service }) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The Prompt for AI agents |
||
| }) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: This commit is titled 'report volume changes accurately', but the added tests still exercise none of the new path-only write rendering:
volumeWriteLinebranches forpending/appliedMountPathandchanged === false/attached(compute.ts 678-690) and thevolumeLinespending line (compute.ts 664-665) get no assertion. The modified path-only test checks only the PUT request body against the defaultrawRequestmock, whose fixed{ attached: true, volume: {sizeGib:1, mountPath:'/app/storage'} }shape never produces a pending or no-op outcome, so the branches the PR claims are unverified. Add assertions onvolumeWriteLine/read output for pending-path and unchanged cases.Prompt for AI agents