mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 08:03:39 +00:00
* fix(github): align PR source and review head origin * fix(github): pin number-based work item open to the repo source preference Open-by-number and details still ran the upstream-first multi-candidate PR probe, so a fork and its upstream sharing a PR number opened different PRs than the list and start-point paths did once #10677 pinned those to origin. Thread repo.issueSourcePreference through dispatchWorkItem, getWorkItemDetails, getRepoWorkItem, and getRepoWorkItemDetails. getWorkItemByOwnerRepo is left alone: explicit owner/repo already pins identity. auto/upstream/undefined keep the multi-candidate probe. Co-authored-by: Orca <help@stably.ai> * test(github): enforce origin preference in review head origin resolution The explicit origin preference must short-circuit before any identity probe, so no remote queries should occur. Add validation to reject unexpected remotes and tighten the test assertion to verify no remote get-url calls happen at all. * fix(github): enforce origin preference in issue open-by-number lookup listWorkItems and getWorkItem must share preference so origin/upstream toggles cannot disagree. Explicit origin preference now fail-closes when origin identity is unresolved (no bare-lookup fallback), matching the PR candidate resolution rule. --------- Co-authored-by: Orca <help@stably.ai>
132 lines
4.5 KiB
TypeScript
132 lines
4.5 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const { getDefaultRemoteMock, getGitHubApiRepositoryForRemoteMock } = vi.hoisted(() => ({
|
|
getDefaultRemoteMock: vi.fn(),
|
|
getGitHubApiRepositoryForRemoteMock: vi.fn()
|
|
}))
|
|
|
|
vi.mock('../git/repo', () => ({ getDefaultRemote: getDefaultRemoteMock }))
|
|
vi.mock('./github-api-repository', () => ({
|
|
getGitHubApiRepositoryForRemote: getGitHubApiRepositoryForRemoteMock
|
|
}))
|
|
|
|
import { resolveGitHubReviewHeadRemote } from './review-head-remote'
|
|
|
|
function gitExecWithRemotes(remotes: string[]) {
|
|
return vi.fn(async (args: string[]) => {
|
|
if (args[0] === 'remote') {
|
|
return { stdout: `${remotes.join('\n')}\n`, stderr: '' }
|
|
}
|
|
throw new Error(`unexpected git call: ${args.join(' ')}`)
|
|
})
|
|
}
|
|
|
|
describe('resolveGitHubReviewHeadRemote', () => {
|
|
beforeEach(() => {
|
|
getDefaultRemoteMock.mockReset()
|
|
getGitHubApiRepositoryForRemoteMock.mockReset()
|
|
})
|
|
|
|
it('prefers upstream on a contributor clone whose origin is a fork', async () => {
|
|
// Why: PR work-item resolution probes upstream first; refs/pull/<N>/head for
|
|
// an upstream PR does not exist on the fork origin.
|
|
getGitHubApiRepositoryForRemoteMock.mockImplementation(async (_path, remote) =>
|
|
remote === 'upstream'
|
|
? { owner: 'org', repo: 'project' }
|
|
: { owner: 'contributor', repo: 'project' }
|
|
)
|
|
|
|
const remote = await resolveGitHubReviewHeadRemote({
|
|
repoPath: '/repo',
|
|
issueSourcePreference: 'auto',
|
|
gitExec: gitExecWithRemotes(['origin', 'upstream'])
|
|
})
|
|
|
|
expect(remote).toBe('upstream')
|
|
expect(getDefaultRemoteMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('falls back to origin when upstream is not a GitHub project', async () => {
|
|
getGitHubApiRepositoryForRemoteMock.mockImplementation(async (_path, remote) =>
|
|
remote === 'origin' ? { owner: 'org', repo: 'project' } : null
|
|
)
|
|
|
|
const remote = await resolveGitHubReviewHeadRemote({
|
|
repoPath: '/repo',
|
|
issueSourcePreference: 'upstream',
|
|
gitExec: gitExecWithRemotes(['origin', 'upstream'])
|
|
})
|
|
|
|
expect(remote).toBe('origin')
|
|
})
|
|
|
|
it('uses explicit origin without probing hosting identity on a dual-remote clone', async () => {
|
|
getGitHubApiRepositoryForRemoteMock.mockResolvedValue({ owner: 'org', repo: 'project' })
|
|
|
|
const remote = await resolveGitHubReviewHeadRemote({
|
|
repoPath: '/repo',
|
|
issueSourcePreference: 'origin',
|
|
gitExec: gitExecWithRemotes(['origin', 'upstream'])
|
|
})
|
|
|
|
expect(remote).toBe('origin')
|
|
expect(getGitHubApiRepositoryForRemoteMock).not.toHaveBeenCalled()
|
|
expect(getDefaultRemoteMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('rejects explicit origin when that remote is not configured', async () => {
|
|
await expect(
|
|
resolveGitHubReviewHeadRemote({
|
|
repoPath: '/repo',
|
|
issueSourcePreference: 'origin',
|
|
gitExec: gitExecWithRemotes(['upstream'])
|
|
})
|
|
).rejects.toThrow('Repo has no configured origin remote.')
|
|
|
|
expect(getGitHubApiRepositoryForRemoteMock).not.toHaveBeenCalled()
|
|
expect(getDefaultRemoteMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('skips identity probes for a single-remote clone and uses the local default', async () => {
|
|
getDefaultRemoteMock.mockResolvedValue('origin')
|
|
|
|
const remote = await resolveGitHubReviewHeadRemote({
|
|
repoPath: '/repo',
|
|
localGitOptions: { wslDistro: 'Ubuntu' },
|
|
gitExec: gitExecWithRemotes(['origin'])
|
|
})
|
|
|
|
expect(remote).toBe('origin')
|
|
expect(getGitHubApiRepositoryForRemoteMock).not.toHaveBeenCalled()
|
|
expect(getDefaultRemoteMock).toHaveBeenCalledWith('/repo', { wslDistro: 'Ubuntu' })
|
|
})
|
|
|
|
it('prefers origin over other remotes on SSH repos when no identity resolves', async () => {
|
|
getGitHubApiRepositoryForRemoteMock.mockResolvedValue(null)
|
|
|
|
const remote = await resolveGitHubReviewHeadRemote({
|
|
repoPath: '/remote/repo',
|
|
connectionId: 'ssh-1',
|
|
gitExec: gitExecWithRemotes(['fork', 'origin'])
|
|
})
|
|
|
|
expect(remote).toBe('origin')
|
|
expect(getDefaultRemoteMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('threads connection and WSL options through the identity probe', async () => {
|
|
getGitHubApiRepositoryForRemoteMock.mockResolvedValue({ owner: 'org', repo: 'project' })
|
|
|
|
await resolveGitHubReviewHeadRemote({
|
|
repoPath: '/repo',
|
|
connectionId: 'ssh-1',
|
|
localGitOptions: { wslDistro: 'Ubuntu' },
|
|
gitExec: gitExecWithRemotes(['origin', 'upstream'])
|
|
})
|
|
|
|
expect(getGitHubApiRepositoryForRemoteMock).toHaveBeenCalledWith('/repo', 'upstream', 'ssh-1', {
|
|
wslDistro: 'Ubuntu'
|
|
})
|
|
})
|
|
})
|