mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 17:17:38 +00:00
refactor(providers): an ssh: route carries no provider and throws one typed error (#27477)
Co-authored-by: m4air <m4air@Mac.localdomain>
This commit is contained in:
@@ -155,24 +155,6 @@ describe('getPRForBranch SSH execution boundary', () => {
|
||||
expect(outcome).toMatchObject({ kind: 'no-pr' })
|
||||
})
|
||||
|
||||
it('rev-parses HEAD through the SSH provider when it is registered', async () => {
|
||||
const sshGitProvider = {
|
||||
exec: vi.fn(async (args: string[]) =>
|
||||
args[0] === 'rev-parse' && args[1] === 'HEAD'
|
||||
? { stdout: `${MERGED_HEAD_OID}\n`, stderr: '' }
|
||||
: { stdout: '', stderr: '' }
|
||||
)
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(sshGitProvider)
|
||||
mockMergedBranchPRLookup()
|
||||
|
||||
const pr = await getPRForBranch('/remote/repo', MERGED_BRANCH, null, 'ssh-1')
|
||||
|
||||
expect(sshGitProvider.exec).toHaveBeenCalledWith(['rev-parse', 'HEAD'], '/remote/repo')
|
||||
expect(gitExecFileAsyncMock).not.toHaveBeenCalled()
|
||||
expect(pr).toMatchObject({ number: 5875, state: 'merged', headSha: MERGED_HEAD_OID })
|
||||
})
|
||||
|
||||
it('rev-parses HEAD through the local runtime for a WSL repository', async () => {
|
||||
mockMergedBranchPRLookup()
|
||||
gitExecFileAsyncMock.mockResolvedValue({ stdout: `${MERGED_HEAD_OID}\n`, stderr: '' })
|
||||
@@ -227,25 +209,6 @@ describe('getPRForBranch SSH execution boundary', () => {
|
||||
expect(outcome).toMatchObject({ kind: 'upstream-error', errorType: 'unknown' })
|
||||
})
|
||||
|
||||
it('reads tracked upstreams through the SSH provider when it is registered', async () => {
|
||||
const forEachRefArgs = ['for-each-ref', '--format=%(refname)%00%(upstream)', 'refs/heads']
|
||||
const sshGitProvider = {
|
||||
exec: vi.fn(async (args: string[]) =>
|
||||
args[0] === 'for-each-ref'
|
||||
? { stdout: `${MERGED_BRANCH}\0origin/contributor/original\n`, stderr: '' }
|
||||
: { stdout: '', stderr: '' }
|
||||
)
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(sshGitProvider)
|
||||
mockUpstreamOnlyPRLookup()
|
||||
|
||||
const pr = await getPRForBranch('/remote/repo', MERGED_BRANCH, null, 'ssh-1')
|
||||
|
||||
expect(sshGitProvider.exec).toHaveBeenCalledWith(forEachRefArgs, '/remote/repo')
|
||||
expect(gitExecFileAsyncMock).not.toHaveBeenCalled()
|
||||
expect(pr).toMatchObject({ number: 78, title: 'Hydrated upstream branch PR' })
|
||||
})
|
||||
|
||||
it('reads tracked upstreams through the local runtime for a WSL repository', async () => {
|
||||
const forEachRefArgs = ['for-each-ref', '--format=%(refname)%00%(upstream)', 'refs/heads']
|
||||
mockUpstreamOnlyPRLookup()
|
||||
|
||||
@@ -31,11 +31,9 @@ import { resetPRForBranchMocks } from './client-test-harness'
|
||||
|
||||
const {
|
||||
ghExecFileAsyncMock,
|
||||
getOwnerRepoMock,
|
||||
getOwnerRepoForRemoteMock,
|
||||
resolvePRRepositoryCandidatesMock,
|
||||
gitExecFileAsyncMock,
|
||||
getSshGitProviderMock
|
||||
gitExecFileAsyncMock
|
||||
} = clientMocks
|
||||
|
||||
describe('getPRForBranch', () => {
|
||||
@@ -200,178 +198,4 @@ describe('getPRForBranch', () => {
|
||||
{ cwd: '/repo-root' }
|
||||
)
|
||||
})
|
||||
|
||||
it('checks the tracked upstream branch through the SSH git provider', async () => {
|
||||
const sshGitProvider = {
|
||||
exec: vi.fn().mockResolvedValue({
|
||||
stdout: 'local-created-from-pr\0origin/contributor/original\n',
|
||||
stderr: ''
|
||||
})
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(sshGitProvider)
|
||||
getOwnerRepoMock.mockResolvedValueOnce({ owner: 'acme', repo: 'widgets' })
|
||||
getOwnerRepoForRemoteMock.mockResolvedValueOnce({ owner: 'acme', repo: 'widgets' })
|
||||
ghExecFileAsyncMock
|
||||
.mockResolvedValueOnce({ stdout: JSON.stringify([]) })
|
||||
.mockResolvedValueOnce({
|
||||
stdout: JSON.stringify([
|
||||
{
|
||||
number: 78,
|
||||
title: 'SSH upstream branch PR',
|
||||
state: 'open',
|
||||
html_url: 'https://github.com/acme/widgets/pull/78',
|
||||
updated_at: '2026-03-28T00:00:00Z',
|
||||
draft: false,
|
||||
mergeable: true,
|
||||
base: { ref: 'main', sha: 'base-oid' },
|
||||
head: { ref: 'contributor/original', sha: 'upstream-head-oid' }
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
const pr = await getPRForBranch(
|
||||
'/remote/repo-root',
|
||||
'local-created-from-pr',
|
||||
undefined,
|
||||
'ssh-1'
|
||||
)
|
||||
|
||||
expect(sshGitProvider.exec).toHaveBeenCalledWith(
|
||||
['for-each-ref', '--format=%(refname)%00%(upstream)', 'refs/heads'],
|
||||
'/remote/repo-root'
|
||||
)
|
||||
expect(gitExecFileAsyncMock).not.toHaveBeenCalled()
|
||||
expect(ghExecFileAsyncMock).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
['api', 'repos/acme/widgets/pulls?head=acme%3Acontributor%2Foriginal&state=all&per_page=1'],
|
||||
{}
|
||||
)
|
||||
expect(pr).toMatchObject({ number: 78, title: 'SSH upstream branch PR' })
|
||||
})
|
||||
|
||||
it('uses the same-name tracked upstream fork owner through the SSH git provider', async () => {
|
||||
const sshGitProvider = {
|
||||
exec: vi.fn().mockResolvedValue({
|
||||
stdout: 'contributor/fix\0fork/contributor/fix\n',
|
||||
stderr: ''
|
||||
})
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(sshGitProvider)
|
||||
resolvePRRepositoryCandidatesMock.mockResolvedValueOnce({
|
||||
candidates: [
|
||||
{ owner: 'stablyai', repo: 'orca' },
|
||||
{ owner: 'origin-owner', repo: 'orca' }
|
||||
],
|
||||
headRepo: { owner: 'origin-owner', repo: 'orca' }
|
||||
})
|
||||
getOwnerRepoForRemoteMock.mockResolvedValueOnce({ owner: 'fork-owner', repo: 'orca' })
|
||||
ghExecFileAsyncMock
|
||||
.mockResolvedValueOnce({ stdout: JSON.stringify([]) })
|
||||
.mockResolvedValueOnce({ stdout: JSON.stringify([]) })
|
||||
.mockResolvedValueOnce({
|
||||
stdout: JSON.stringify([
|
||||
{
|
||||
number: 79,
|
||||
title: 'SSH same-name fork PR',
|
||||
state: 'open',
|
||||
html_url: 'https://github.com/stablyai/orca/pull/79',
|
||||
updated_at: '2026-03-28T00:00:00Z',
|
||||
draft: false,
|
||||
mergeable: true,
|
||||
base: { ref: 'main', sha: 'base-oid' },
|
||||
head: { ref: 'contributor/fix', sha: 'same-name-ssh-head-oid' }
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
const pr = await getPRForBranch('/remote/repo-root', 'contributor/fix', undefined, 'ssh-1')
|
||||
|
||||
expect(getOwnerRepoForRemoteMock).toHaveBeenCalledWith('/remote/repo-root', 'fork', 'ssh-1')
|
||||
expect(ghExecFileAsyncMock).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
['api', 'repos/stablyai/orca/pulls?head=fork-owner%3Acontributor%2Ffix&state=all&per_page=1'],
|
||||
{}
|
||||
)
|
||||
expect(pr).toMatchObject({
|
||||
number: 79,
|
||||
title: 'SSH same-name fork PR',
|
||||
prRepo: { owner: 'stablyai', repo: 'orca' },
|
||||
headRepo: { owner: 'fork-owner', repo: 'orca' }
|
||||
})
|
||||
})
|
||||
|
||||
it('caches positive tracked-upstream entries for unsigned SSH runtimes during PR refresh polling', async () => {
|
||||
const sshGitProvider = {
|
||||
exec: vi.fn().mockResolvedValue({
|
||||
stdout: 'refs/heads/feature\0origin/contributor/original\n',
|
||||
stderr: ''
|
||||
})
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(sshGitProvider)
|
||||
getOwnerRepoMock.mockResolvedValue({ owner: 'acme', repo: 'widgets' })
|
||||
getOwnerRepoForRemoteMock.mockResolvedValue({ owner: 'acme', repo: 'widgets' })
|
||||
ghExecFileAsyncMock.mockResolvedValue({ stdout: JSON.stringify([]) })
|
||||
|
||||
await getPRForBranch('/remote/repo-root', 'feature', undefined, 'ssh-1')
|
||||
await getPRForBranch('/remote/repo-root', 'feature', undefined, 'ssh-1')
|
||||
await getPRForBranch('/remote/repo-root', 'feature', undefined, 'ssh-1')
|
||||
|
||||
expect(sshGitProvider.exec).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('refreshes positive tracked-upstream entries for unsigned SSH runtimes after the TTL', async () => {
|
||||
vi.useFakeTimers()
|
||||
try {
|
||||
const sshGitProvider = {
|
||||
exec: vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
stdout: 'refs/heads/feature\0origin/old-upstream\n',
|
||||
stderr: ''
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
stdout: 'refs/heads/feature\0origin/contributor/original\n',
|
||||
stderr: ''
|
||||
})
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(sshGitProvider)
|
||||
getOwnerRepoMock.mockResolvedValue({ owner: 'acme', repo: 'widgets' })
|
||||
getOwnerRepoForRemoteMock.mockResolvedValue({ owner: 'acme', repo: 'widgets' })
|
||||
ghExecFileAsyncMock
|
||||
.mockResolvedValueOnce({ stdout: JSON.stringify([]) })
|
||||
.mockResolvedValueOnce({ stdout: JSON.stringify([]) })
|
||||
.mockResolvedValueOnce({ stdout: JSON.stringify([]) })
|
||||
.mockResolvedValueOnce({
|
||||
stdout: JSON.stringify([
|
||||
{
|
||||
number: 81,
|
||||
title: 'Fresh SSH upstream PR',
|
||||
state: 'open',
|
||||
html_url: 'https://github.com/acme/widgets/pull/81',
|
||||
updated_at: '2026-03-28T00:00:00Z',
|
||||
draft: false,
|
||||
mergeable: true,
|
||||
base: { ref: 'main', sha: 'base-oid' },
|
||||
head: { ref: 'contributor/original', sha: 'upstream-head-oid' }
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
await getPRForBranch('/remote/repo-root', 'feature', undefined, 'ssh-1')
|
||||
await vi.advanceTimersByTimeAsync(30_001)
|
||||
const pr = await getPRForBranch('/remote/repo-root', 'feature', undefined, 'ssh-1')
|
||||
|
||||
// Why: a found upstream PR also resolves the default branch (#26948); count snapshot probes only.
|
||||
const snapshotProbes = sshGitProvider.exec.mock.calls.filter(([args]) =>
|
||||
args.includes('refs/heads')
|
||||
)
|
||||
expect(snapshotProbes).toHaveLength(2)
|
||||
expect(pr).toMatchObject({
|
||||
number: 81,
|
||||
title: 'Fresh SSH upstream PR'
|
||||
})
|
||||
} finally {
|
||||
vi.useRealTimers()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -39,7 +39,6 @@ const {
|
||||
getOwnerRepoForRemoteMock,
|
||||
resolvePRRepositoryCandidatesMock,
|
||||
gitExecFileAsyncMock,
|
||||
getSshGitProviderMock,
|
||||
readLocalGitConfigSignatureMock
|
||||
} = clientMocks
|
||||
|
||||
@@ -143,10 +142,6 @@ describe('getPRForBranch', () => {
|
||||
})
|
||||
|
||||
it('releases tracked-upstream probe generations across runtime identities', async () => {
|
||||
const sshGitProvider = {
|
||||
exec: vi.fn().mockResolvedValue({ stdout: 'feature\0\n', stderr: '' })
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(sshGitProvider)
|
||||
getOwnerRepoMock.mockResolvedValue({ owner: 'acme', repo: 'widgets' })
|
||||
ghExecFileAsyncMock.mockResolvedValue({ stdout: JSON.stringify([]) })
|
||||
gitExecFileAsyncMock.mockResolvedValue({ stdout: 'feature\0\n', stderr: '' })
|
||||
@@ -155,15 +150,13 @@ describe('getPRForBranch', () => {
|
||||
await getPRForBranch('/repo-root', 'feature', null, null, null, {
|
||||
localGitExecOptions: { wslDistro: 'Ubuntu' }
|
||||
})
|
||||
await getPRForBranch('/repo-root', 'feature', null, 'ssh-1')
|
||||
|
||||
expect(_getTrackedUpstreamBranchCacheSizesForTests()).toEqual({
|
||||
snapshots: 3,
|
||||
snapshots: 2,
|
||||
inFlight: 0,
|
||||
generations: 0
|
||||
})
|
||||
expect(gitExecFileAsyncMock).toHaveBeenCalledTimes(2)
|
||||
expect(sshGitProvider.exec).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('bounds unique tracked-upstream snapshots and sweeps expired identities', async () => {
|
||||
|
||||
@@ -218,11 +218,7 @@ export async function getCurrentHeadOid(
|
||||
connectionId?: string | null,
|
||||
localGitOptions: { wslDistro?: string; admissionTier?: GitAdmissionTier } = {}
|
||||
): Promise<string | null> {
|
||||
const route = requireReachableGitRoute(getConnectionExecutionHostId(connectionId))
|
||||
if (route.kind === 'ssh') {
|
||||
const result = await route.provider.exec(['rev-parse', 'HEAD'], repoPath)
|
||||
return result.stdout.trim() || null
|
||||
}
|
||||
requireReachableGitRoute(getConnectionExecutionHostId(connectionId))
|
||||
try {
|
||||
const result = await gitExecFileAsync(['rev-parse', 'HEAD'], {
|
||||
cwd: repoPath,
|
||||
|
||||
@@ -134,14 +134,7 @@ export async function probeTrackedUpstreamBranches(
|
||||
upstreamsByBranchName: Map<string, TrackedUpstreamBranch | null>
|
||||
}> {
|
||||
const args = ['for-each-ref', '--format=%(refname)%00%(upstream)', 'refs/heads']
|
||||
const route = requireReachableGitRoute(getConnectionExecutionHostId(connectionId))
|
||||
if (route.kind === 'ssh') {
|
||||
const result = await route.provider.exec(args, repoPath)
|
||||
return {
|
||||
probeFailed: false,
|
||||
upstreamsByBranchName: parseTrackedUpstreamBranches(result.stdout)
|
||||
}
|
||||
}
|
||||
requireReachableGitRoute(getConnectionExecutionHostId(connectionId))
|
||||
try {
|
||||
const result = await gitExecFileAsync(args, {
|
||||
cwd: repoPath,
|
||||
|
||||
@@ -193,53 +193,6 @@ describe('#10284 SSH Host alias → github.com owner/repo', () => {
|
||||
expect(gitExecFileAsyncMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('preserves a one-shot SSH remote failure through candidate discovery', async () => {
|
||||
const failure = new Error('relay request failed')
|
||||
const provider = {
|
||||
exec: vi
|
||||
.fn()
|
||||
.mockRejectedValueOnce(failure)
|
||||
.mockResolvedValueOnce({ stdout: 'git@github.com:team/orca.git\n', stderr: '' })
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(provider)
|
||||
|
||||
await expect(
|
||||
getOwnerRepoForRemote(
|
||||
'/remote/repo',
|
||||
'origin',
|
||||
'ssh-1',
|
||||
{},
|
||||
{
|
||||
requireVerifiedSshProbe: true
|
||||
}
|
||||
)
|
||||
).rejects.toBe(failure)
|
||||
await expect(getOwnerRepoForRemote('/remote/repo', 'origin', 'ssh-1')).resolves.toEqual({
|
||||
owner: 'team',
|
||||
repo: 'orca'
|
||||
})
|
||||
expect(provider.exec).toHaveBeenCalledTimes(2)
|
||||
expect(gitExecFileAsyncMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('keeps failed SSH alias classification unverifiable', async () => {
|
||||
const provider = sshProvider('')
|
||||
getSshGitProviderMock.mockReturnValue(provider)
|
||||
|
||||
await expect(
|
||||
getOwnerRepoForRemote(
|
||||
'/remote/repo',
|
||||
'origin',
|
||||
'ssh-1',
|
||||
{},
|
||||
{
|
||||
requireVerifiedSshProbe: true
|
||||
}
|
||||
)
|
||||
).rejects.toThrow('Remote repository identity is unverifiable.')
|
||||
expect(gitExecFileAsyncMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('isolates the same alias across native and WSL runtimes', async () => {
|
||||
resolveWithSshGMock.mockResolvedValueOnce(sshConfig('github.com'))
|
||||
commandExecFileAsyncMock.mockResolvedValueOnce({
|
||||
|
||||
Reference in New Issue
Block a user