mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 00:27:39 +00:00
658 lines
22 KiB
TypeScript
658 lines
22 KiB
TypeScript
/* eslint-disable max-lines -- Why: git RPC methods share one dispatcher fixture, and keeping the contract cases together makes method coverage easy to audit. */
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
import { RpcDispatcher } from '../dispatcher'
|
|
import type { RpcRequest } from '../core'
|
|
import type { OrcaRuntimeService } from '../../orca-runtime'
|
|
import { GIT_METHODS } from './git'
|
|
|
|
function makeRequest(method: string, params?: unknown): RpcRequest {
|
|
return { id: 'req-1', authToken: 'tok', method, params }
|
|
}
|
|
|
|
describe('git RPC methods', () => {
|
|
it('returns status for a selected worktree', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
getRuntimeGitStatus: vi.fn().mockResolvedValue({
|
|
entries: [],
|
|
conflictOperation: 'unknown',
|
|
branch: 'main',
|
|
head: 'abc'
|
|
})
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(makeRequest('git.status', { worktree: 'id:wt-1' }))
|
|
|
|
expect(runtime.getRuntimeGitStatus).toHaveBeenCalledWith('id:wt-1')
|
|
expect(response).toMatchObject({
|
|
ok: true,
|
|
result: { entries: [], branch: 'main' }
|
|
})
|
|
})
|
|
|
|
it('forwards includeIgnored for status requests', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
getRuntimeGitStatus: vi.fn().mockResolvedValue({
|
|
entries: [],
|
|
conflictOperation: 'unknown',
|
|
ignoredPaths: ['dist/']
|
|
})
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.status', { worktree: 'id:wt-1', includeIgnored: true })
|
|
)
|
|
|
|
expect(runtime.getRuntimeGitStatus).toHaveBeenCalledWith('id:wt-1', {
|
|
includeIgnored: true
|
|
})
|
|
expect(response).toMatchObject({
|
|
ok: true,
|
|
result: { ignoredPaths: ['dist/'] }
|
|
})
|
|
})
|
|
|
|
it('returns ignored paths for selected explorer rows', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
checkRuntimeGitIgnoredPaths: vi.fn().mockResolvedValue(['dist/bundle.js'])
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.checkIgnored', {
|
|
worktree: 'id:wt-1',
|
|
paths: ['dist/bundle.js', 'src/index.ts']
|
|
})
|
|
)
|
|
|
|
expect(runtime.checkRuntimeGitIgnoredPaths).toHaveBeenCalledWith('id:wt-1', [
|
|
'dist/bundle.js',
|
|
'src/index.ts'
|
|
])
|
|
expect(response).toMatchObject({
|
|
ok: true,
|
|
result: ['dist/bundle.js']
|
|
})
|
|
})
|
|
|
|
it('returns a worktree file diff', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
getRuntimeGitDiff: vi.fn().mockResolvedValue({
|
|
kind: 'text',
|
|
originalContent: '',
|
|
modifiedContent: 'hello',
|
|
originalIsBinary: false,
|
|
modifiedIsBinary: false
|
|
})
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.diff', {
|
|
worktree: 'id:wt-1',
|
|
filePath: 'src/index.ts',
|
|
staged: false,
|
|
compareAgainstHead: true
|
|
})
|
|
)
|
|
|
|
expect(runtime.getRuntimeGitDiff).toHaveBeenCalledWith('id:wt-1', 'src/index.ts', false, true)
|
|
expect(response).toMatchObject({
|
|
ok: true,
|
|
result: { kind: 'text', modifiedContent: 'hello' }
|
|
})
|
|
})
|
|
|
|
it('returns bounded git history for a selected worktree', async () => {
|
|
const history = {
|
|
items: [],
|
|
hasIncomingChanges: false,
|
|
hasOutgoingChanges: false,
|
|
hasMore: false,
|
|
limit: 50
|
|
}
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
getRuntimeGitHistory: vi.fn().mockResolvedValue(history)
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.history', {
|
|
worktree: 'id:wt-1',
|
|
limit: 25,
|
|
baseRef: 'origin/main'
|
|
})
|
|
)
|
|
|
|
expect(runtime.getRuntimeGitHistory).toHaveBeenCalledWith('id:wt-1', {
|
|
limit: 25,
|
|
baseRef: 'origin/main'
|
|
})
|
|
expect(response).toMatchObject({ ok: true, result: history })
|
|
})
|
|
|
|
it('routes common mutations to the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
stageRuntimeGitPath: vi.fn().mockResolvedValue({ ok: true }),
|
|
bulkUnstageRuntimeGitPaths: vi.fn().mockResolvedValue({ ok: true }),
|
|
discardRuntimeGitPath: vi.fn().mockResolvedValue({ ok: true }),
|
|
bulkDiscardRuntimeGitPaths: vi.fn().mockResolvedValue({ ok: true })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.stage', { worktree: 'id:wt-1', filePath: 'src/a.ts' })
|
|
)
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.bulkUnstage', { worktree: 'id:wt-1', filePaths: ['src/a.ts', 'b.ts'] })
|
|
)
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.discard', { worktree: 'id:wt-1', filePath: 'src/a.ts' })
|
|
)
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.bulkDiscard', { worktree: 'id:wt-1', filePaths: ['src/a.ts', 'b.ts'] })
|
|
)
|
|
|
|
expect(runtime.stageRuntimeGitPath).toHaveBeenCalledWith('id:wt-1', 'src/a.ts')
|
|
expect(runtime.bulkUnstageRuntimeGitPaths).toHaveBeenCalledWith('id:wt-1', ['src/a.ts', 'b.ts'])
|
|
expect(runtime.discardRuntimeGitPath).toHaveBeenCalledWith('id:wt-1', 'src/a.ts')
|
|
expect(runtime.bulkDiscardRuntimeGitPaths).toHaveBeenCalledWith('id:wt-1', ['src/a.ts', 'b.ts'])
|
|
})
|
|
|
|
it('rejects empty bulk mutation paths before calling the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
bulkDiscardRuntimeGitPaths: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.bulkDiscard', { worktree: 'id:wt-1', filePaths: [''] })
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(response).toMatchObject({
|
|
error: expect.objectContaining({ code: 'invalid_argument' })
|
|
})
|
|
expect(runtime.bulkDiscardRuntimeGitPaths).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('routes remote operations to the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
commitRuntimeGit: vi.fn().mockResolvedValue({ success: true }),
|
|
generateRuntimeCommitMessage: vi
|
|
.fn()
|
|
.mockResolvedValue({ success: true, message: 'feat: test' }),
|
|
discoverRuntimeCommitMessageModels: vi.fn().mockResolvedValue({
|
|
success: true,
|
|
models: [{ id: 'auto', label: 'Auto' }],
|
|
defaultModelId: 'auto'
|
|
}),
|
|
cancelRuntimeGenerateCommitMessage: vi.fn().mockResolvedValue({ ok: true }),
|
|
abortRuntimeGitMerge: vi.fn().mockResolvedValue({ ok: true }),
|
|
abortRuntimeGitRebase: vi.fn().mockResolvedValue({ ok: true }),
|
|
pushRuntimeGit: vi.fn().mockResolvedValue({ ok: true }),
|
|
getRuntimeGitRemoteFileUrl: vi.fn().mockResolvedValue('https://example.com/file#L3'),
|
|
getRuntimeGitRemoteCommitUrl: vi.fn().mockResolvedValue('https://example.com/commit/abc')
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
const commitOid = '0123456789abcdef0123456789abcdef01234567'
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.commit', { worktree: 'id:wt-1', message: 'feat: test' })
|
|
)
|
|
await dispatcher.dispatch(makeRequest('git.generateCommitMessage', { worktree: 'id:wt-1' }))
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.discoverCommitMessageModels', {
|
|
worktree: 'id:wt-1',
|
|
agentId: 'cursor',
|
|
agentCmdOverrides: { cursor: 'cursor-agent' }
|
|
})
|
|
)
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.cancelGenerateCommitMessage', { worktree: 'id:wt-1' })
|
|
)
|
|
await dispatcher.dispatch(makeRequest('git.abortMerge', { worktree: 'id:wt-1' }))
|
|
await dispatcher.dispatch(makeRequest('git.abortRebase', { worktree: 'id:wt-1' }))
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.push', {
|
|
worktree: 'id:wt-1',
|
|
publish: true,
|
|
pushTarget: { remoteName: 'origin', branchName: 'feature' }
|
|
})
|
|
)
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.remoteFileUrl', {
|
|
worktree: 'id:wt-1',
|
|
relativePath: 'src/a.ts',
|
|
line: 3
|
|
})
|
|
)
|
|
const commitUrlResponse = await dispatcher.dispatch(
|
|
makeRequest('git.remoteCommitUrl', {
|
|
worktree: 'id:wt-1',
|
|
sha: commitOid
|
|
})
|
|
)
|
|
|
|
expect(runtime.commitRuntimeGit).toHaveBeenCalledWith('id:wt-1', 'feat: test')
|
|
expect(runtime.generateRuntimeCommitMessage).toHaveBeenCalledWith('id:wt-1')
|
|
expect(runtime.discoverRuntimeCommitMessageModels).toHaveBeenCalledWith('id:wt-1', 'cursor', {
|
|
agentCmdOverrides: { cursor: 'cursor-agent' }
|
|
})
|
|
expect(runtime.cancelRuntimeGenerateCommitMessage).toHaveBeenCalledWith('id:wt-1')
|
|
expect(runtime.abortRuntimeGitMerge).toHaveBeenCalledWith('id:wt-1')
|
|
expect(runtime.abortRuntimeGitRebase).toHaveBeenCalledWith('id:wt-1')
|
|
expect(runtime.pushRuntimeGit).toHaveBeenCalledWith(
|
|
'id:wt-1',
|
|
true,
|
|
{ remoteName: 'origin', branchName: 'feature' },
|
|
undefined
|
|
)
|
|
expect(response).toMatchObject({ ok: true, result: 'https://example.com/file#L3' })
|
|
expect(runtime.getRuntimeGitRemoteCommitUrl).toHaveBeenCalledWith('id:wt-1', commitOid)
|
|
expect(commitUrlResponse).toMatchObject({ ok: true, result: 'https://example.com/commit/abc' })
|
|
})
|
|
|
|
it('rejects remote commit URL requests without a full git object id', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
getRuntimeGitRemoteCommitUrl: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.remoteCommitUrl', {
|
|
worktree: 'id:wt-1',
|
|
sha: 'abc123'
|
|
})
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(runtime.getRuntimeGitRemoteCommitUrl).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('forwards force-with-lease push mode to the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
pushRuntimeGit: vi.fn().mockResolvedValue({ ok: true })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.push', {
|
|
worktree: 'id:wt-1',
|
|
forceWithLease: true
|
|
})
|
|
)
|
|
|
|
expect(runtime.pushRuntimeGit).toHaveBeenCalledWith('id:wt-1', undefined, undefined, true)
|
|
})
|
|
|
|
it('forwards rebase-from-base to the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
rebaseRuntimeGitFromBase: vi.fn().mockResolvedValue({ ok: true })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.rebaseFromBase', {
|
|
worktree: 'id:wt-1',
|
|
baseRef: 'origin/main'
|
|
})
|
|
)
|
|
|
|
expect(runtime.rebaseRuntimeGitFromBase).toHaveBeenCalledWith('id:wt-1', 'origin/main')
|
|
})
|
|
|
|
it('forwards fetch push target to the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
fetchRuntimeGit: vi.fn().mockResolvedValue({ ok: true })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
const pushTarget = { remoteName: 'fork', branchName: 'feature' }
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.fetch', {
|
|
worktree: 'id:wt-1',
|
|
pushTarget
|
|
})
|
|
)
|
|
|
|
expect(runtime.fetchRuntimeGit).toHaveBeenCalledWith('id:wt-1', pushTarget)
|
|
})
|
|
|
|
it('forwards fork sync requests to the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
syncRuntimeGitForkDefaultBranch: vi.fn().mockResolvedValue({
|
|
status: 'up-to-date',
|
|
originRemote: 'origin',
|
|
upstreamRemote: 'upstream',
|
|
branchName: 'main',
|
|
ahead: 0,
|
|
behind: 0
|
|
})
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.forkSync', {
|
|
worktree: 'id:wt-1',
|
|
expectedUpstream: { owner: 'stablyai', repo: 'orca' }
|
|
})
|
|
)
|
|
|
|
expect(runtime.syncRuntimeGitForkDefaultBranch).toHaveBeenCalledWith('id:wt-1', {
|
|
owner: 'stablyai',
|
|
repo: 'orca'
|
|
})
|
|
expect(response).toMatchObject({
|
|
ok: true,
|
|
result: { status: 'up-to-date', branchName: 'main', ahead: 0, behind: 0 }
|
|
})
|
|
})
|
|
|
|
it('rejects blank fork sync expected upstream fields before calling the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
syncRuntimeGitForkDefaultBranch: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.forkSync', {
|
|
worktree: 'id:wt-1',
|
|
expectedUpstream: { owner: ' ', repo: 'orca' }
|
|
})
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(response).toMatchObject({
|
|
error: expect.objectContaining({ code: 'invalid_argument' })
|
|
})
|
|
expect(runtime.syncRuntimeGitForkDefaultBranch).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('rejects missing fork sync expected upstream before calling the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
syncRuntimeGitForkDefaultBranch: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.forkSync', {
|
|
worktree: 'id:wt-1'
|
|
})
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(response).toMatchObject({
|
|
error: expect.objectContaining({ code: 'invalid_argument' })
|
|
})
|
|
expect(runtime.syncRuntimeGitForkDefaultBranch).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('forwards fast-forward push target to the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
fastForwardRuntimeGit: vi.fn().mockResolvedValue({ ok: true })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
const pushTarget = { remoteName: 'fork', branchName: 'feature' }
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.fastForward', {
|
|
worktree: 'id:wt-1',
|
|
pushTarget
|
|
})
|
|
)
|
|
|
|
expect(runtime.fastForwardRuntimeGit).toHaveBeenCalledWith('id:wt-1', pushTarget)
|
|
})
|
|
|
|
it('forwards commit-message settings to the runtime', async () => {
|
|
const commitMessageAi = {
|
|
enabled: true,
|
|
agentId: 'codex',
|
|
selectedModelByAgent: { codex: 'gpt-5.3-codex-spark' },
|
|
selectedModelByAgentByHost: { 'ssh:conn-1': { cursor: 'remote-model' } },
|
|
discoveredModelsByAgent: {
|
|
cursor: [{ id: 'local-model', label: 'Local Model' }]
|
|
},
|
|
discoveredModelsByAgentByHost: {
|
|
'ssh:conn-1': {
|
|
cursor: [{ id: 'remote-model', label: 'Remote Model' }]
|
|
}
|
|
},
|
|
selectedThinkingByModel: { 'gpt-5.3-codex-spark': 'medium' },
|
|
customPrompt: '',
|
|
customAgentCommand: ''
|
|
}
|
|
const agentCmdOverrides = { codex: 'codex --profile work' }
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
generateRuntimeCommitMessage: vi.fn().mockResolvedValue({ success: true, message: 'test' })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.generateCommitMessage', {
|
|
worktree: 'id:wt-1',
|
|
commitMessageAi,
|
|
agentCmdOverrides,
|
|
enableGitHubAttribution: true,
|
|
commitMessageDiscoveryHostKey: 'runtime:env-1'
|
|
})
|
|
)
|
|
|
|
expect(runtime.generateRuntimeCommitMessage).toHaveBeenCalledWith('id:wt-1', {
|
|
commitMessageAi,
|
|
agentCmdOverrides,
|
|
enableGitHubAttribution: true,
|
|
commitMessageDiscoveryHostKey: 'runtime:env-1'
|
|
})
|
|
})
|
|
|
|
it('forwards one-shot commit-message params to the runtime', async () => {
|
|
const sourceControlAiResolvedParams = {
|
|
agentId: 'codex',
|
|
model: 'gpt-5.5',
|
|
thinkingLevel: 'high',
|
|
customPrompt: 'Use Conventional Commits.'
|
|
}
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
generateRuntimeCommitMessage: vi.fn().mockResolvedValue({ success: true, message: 'test' })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.generateCommitMessage', {
|
|
worktree: 'id:wt-1',
|
|
sourceControlAiResolvedParams
|
|
})
|
|
)
|
|
|
|
expect(runtime.generateRuntimeCommitMessage).toHaveBeenCalledWith('id:wt-1', {
|
|
sourceControlAiResolvedParams
|
|
})
|
|
})
|
|
|
|
it('forwards one-shot pull-request generation params to the runtime', async () => {
|
|
const sourceControlAiResolvedParams = {
|
|
agentId: 'codex',
|
|
model: 'gpt-5.5',
|
|
thinkingLevel: 'high',
|
|
commandInputTemplate: '{basePrompt}\n\nUse release-note style.'
|
|
}
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
generateRuntimePullRequestFields: vi
|
|
.fn()
|
|
.mockResolvedValue({ success: true, fields: { title: 'Test', body: '', draft: false } })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
await dispatcher.dispatch(
|
|
makeRequest('git.generatePullRequestFields', {
|
|
worktree: 'id:wt-1',
|
|
base: 'main',
|
|
title: '',
|
|
body: '',
|
|
draft: false,
|
|
sourceControlAiResolvedParams
|
|
})
|
|
)
|
|
|
|
expect(runtime.generateRuntimePullRequestFields).toHaveBeenCalledWith(
|
|
'id:wt-1',
|
|
{ base: 'main', title: '', body: '', draft: false },
|
|
{ sourceControlAiResolvedParams }
|
|
)
|
|
})
|
|
|
|
it('rejects malformed commit-message settings before calling the runtime', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
generateRuntimeCommitMessage: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.generateCommitMessage', {
|
|
worktree: 'id:wt-1',
|
|
commitMessageAi: {
|
|
enabled: true,
|
|
agentId: 'codex'
|
|
}
|
|
})
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(response).toMatchObject({
|
|
error: expect.objectContaining({ code: 'invalid_argument' })
|
|
})
|
|
expect(runtime.generateRuntimeCommitMessage).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('rejects branch diff revisions that are not full object ids', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
getRuntimeGitBranchDiff: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.branchDiff', {
|
|
worktree: 'id:wt-1',
|
|
filePath: 'src/a.ts',
|
|
compare: {
|
|
headOid: '--output=/tmp/orca-test',
|
|
mergeBase: 'a'.repeat(40)
|
|
}
|
|
})
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(runtime.getRuntimeGitBranchDiff).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('rejects branch compare refs that look like git options', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
getRuntimeGitBranchCompare: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.branchCompare', {
|
|
worktree: 'id:wt-1',
|
|
baseRef: '--output=/tmp/orca-test'
|
|
})
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(runtime.getRuntimeGitBranchCompare).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('rejects git history limits above the runtime cap', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
getRuntimeGitHistory: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.history', {
|
|
worktree: 'id:wt-1',
|
|
limit: 201
|
|
})
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(runtime.getRuntimeGitHistory).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('checks out a branch', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
checkoutRuntimeGitBranch: vi.fn().mockResolvedValue({ ok: true, branch: 'feature/x' })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.checkout', { worktree: 'id:wt-1', branch: 'feature/x' })
|
|
)
|
|
|
|
expect(runtime.checkoutRuntimeGitBranch).toHaveBeenCalledWith('id:wt-1', 'feature/x')
|
|
expect(response).toMatchObject({ ok: true, result: { ok: true, branch: 'feature/x' } })
|
|
})
|
|
|
|
it('rejects a checkout branch that starts with a dash', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
checkoutRuntimeGitBranch: vi.fn()
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.checkout', { worktree: 'id:wt-1', branch: '--force' })
|
|
)
|
|
|
|
expect(response.ok).toBe(false)
|
|
expect(runtime.checkoutRuntimeGitBranch).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('lists local branches', async () => {
|
|
const runtime = {
|
|
getRuntimeId: () => 'test-runtime',
|
|
listRuntimeGitLocalBranches: vi
|
|
.fn()
|
|
.mockResolvedValue({ current: 'main', branches: ['main', 'feature/x'] })
|
|
} as unknown as OrcaRuntimeService
|
|
const dispatcher = new RpcDispatcher({ runtime, methods: GIT_METHODS })
|
|
|
|
const response = await dispatcher.dispatch(
|
|
makeRequest('git.localBranches', { worktree: 'id:wt-1' })
|
|
)
|
|
|
|
expect(runtime.listRuntimeGitLocalBranches).toHaveBeenCalledWith('id:wt-1')
|
|
expect(response).toMatchObject({
|
|
ok: true,
|
|
result: { current: 'main', branches: ['main', 'feature/x'] }
|
|
})
|
|
})
|
|
})
|