Files
orca/src/main/source-control/forge-provider.test.ts
T
Jinjing 97dc6d63e3 Accept merged fallback PRs during branch lookup (#5908)
Ensure that when a visible fallback PR has been merged (e.g., outside
Orca with a deleted head branch), it is still accepted and refreshed by
branch lookup instead of being discarded as an implicit merged PR.

* Add `acceptMergedFallbackPR` option to GitHub branch lookups
* Enable this option during manual and background refreshes of fallback PRs
* Plumb the new option through preload APIs, IPC handlers, and RPC protocols
2026-06-20 03:30:18 -07:00

277 lines
7.7 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
const {
createGitHubPullRequestMock,
createGitLabMergeRequestMock,
createAzureDevOpsPullRequestMock,
createGiteaPullRequestMock,
getAzureDevOpsRepoSlugMock,
getBitbucketRepoSlugMock,
getGiteaRepoSlugMock,
getMergeRequestForBranchMock,
getProjectSlugMock,
getPRForBranchMock,
getRepoSlugMock
} = vi.hoisted(() => ({
createGitHubPullRequestMock: vi.fn(),
createGitLabMergeRequestMock: vi.fn(),
createAzureDevOpsPullRequestMock: vi.fn(),
createGiteaPullRequestMock: vi.fn(),
getAzureDevOpsRepoSlugMock: vi.fn(),
getBitbucketRepoSlugMock: vi.fn(),
getGiteaRepoSlugMock: vi.fn(),
getMergeRequestForBranchMock: vi.fn(),
getProjectSlugMock: vi.fn(),
getPRForBranchMock: vi.fn(),
getRepoSlugMock: vi.fn()
}))
vi.mock('../gitlab/client', () => ({
getProjectSlug: getProjectSlugMock,
getMergeRequestForBranch: getMergeRequestForBranchMock,
getMergeRequest: vi.fn()
}))
vi.mock('../gitlab/merge-request-creation', () => ({
createGitLabMergeRequest: createGitLabMergeRequestMock
}))
vi.mock('../github/client', () => ({
createGitHubPullRequest: createGitHubPullRequestMock,
getRepoSlug: getRepoSlugMock,
getPRForBranch: getPRForBranchMock
}))
vi.mock('../bitbucket/client', () => ({
getBitbucketRepoSlug: getBitbucketRepoSlugMock,
getBitbucketPullRequestForBranch: vi.fn(),
getBitbucketPullRequest: vi.fn()
}))
vi.mock('../azure-devops/client', () => ({
getAzureDevOpsRepoSlug: getAzureDevOpsRepoSlugMock,
getAzureDevOpsPullRequestForBranch: vi.fn(),
getAzureDevOpsPullRequest: vi.fn()
}))
vi.mock('../azure-devops/pull-request-creation', () => ({
createAzureDevOpsPullRequest: createAzureDevOpsPullRequestMock
}))
vi.mock('../gitea/client', () => ({
getGiteaRepoSlug: getGiteaRepoSlugMock,
getGiteaPullRequestForBranch: vi.fn(),
getGiteaPullRequest: vi.fn()
}))
vi.mock('../gitea/pull-request-creation', () => ({
createGiteaPullRequest: createGiteaPullRequestMock
}))
import {
FORGE_PROVIDERS,
detectHostedReviewProvider,
getForgeProviderById,
getForgeProviderForRepository
} from './forge-provider'
describe('forge provider interface', () => {
beforeEach(() => {
createGitHubPullRequestMock.mockReset()
createGitLabMergeRequestMock.mockReset()
createAzureDevOpsPullRequestMock.mockReset()
createGiteaPullRequestMock.mockReset()
getAzureDevOpsRepoSlugMock.mockReset()
getBitbucketRepoSlugMock.mockReset()
getGiteaRepoSlugMock.mockReset()
getMergeRequestForBranchMock.mockReset()
getProjectSlugMock.mockReset()
getPRForBranchMock.mockReset()
getRepoSlugMock.mockReset()
})
it('preserves the existing hosted provider detection order', async () => {
getProjectSlugMock.mockResolvedValue({ host: 'gitlab.com', path: 'team/orca' })
getRepoSlugMock.mockResolvedValue({ owner: 'team', repo: 'orca' })
await expect(detectHostedReviewProvider({ repoPath: '/repo' })).resolves.toBe('gitlab')
await expect(getForgeProviderForRepository({ repoPath: '/repo' })).resolves.toMatchObject({
id: 'gitlab'
})
expect(getRepoSlugMock).not.toHaveBeenCalled()
})
it('keeps review creation capability scoped to providers with creation support', async () => {
expect(
FORGE_PROVIDERS.map((provider) => [provider.id, provider.supportsReviewCreation])
).toEqual([
['gitlab', true],
['github', true],
['bitbucket', false],
['azure-devops', true],
['gitea', true]
])
createGitHubPullRequestMock.mockResolvedValue({
ok: true,
number: 12,
url: 'https://github.com/team/orca/pull/12'
})
const provider = getForgeProviderById('github')
await expect(
provider.createReview?.('/repo', {
provider: 'github',
base: 'main',
head: 'feature/provider-interface',
title: 'Add provider interface'
})
).resolves.toEqual({
ok: true,
number: 12,
url: 'https://github.com/team/orca/pull/12'
})
expect(createGitHubPullRequestMock).toHaveBeenCalledWith('/repo', {
provider: 'github',
base: 'main',
head: 'feature/provider-interface',
title: 'Add provider interface'
})
})
it('routes GitLab review creation through the shared provider contract', async () => {
createGitLabMergeRequestMock.mockResolvedValue({
ok: true,
number: 44,
url: 'https://gitlab.com/team/orca/-/merge_requests/44'
})
const provider = getForgeProviderById('gitlab')
await expect(
provider.createReview?.(
'/repo',
{
provider: 'gitlab',
base: 'main',
head: 'feature/provider-interface',
title: 'Add provider interface'
},
'ssh-1'
)
).resolves.toEqual({
ok: true,
number: 44,
url: 'https://gitlab.com/team/orca/-/merge_requests/44'
})
expect(createGitLabMergeRequestMock).toHaveBeenCalledWith(
'/repo',
{
provider: 'gitlab',
base: 'main',
head: 'feature/provider-interface',
title: 'Add provider interface'
},
'ssh-1'
)
})
it('routes Azure DevOps review creation through the shared provider contract', async () => {
createAzureDevOpsPullRequestMock.mockResolvedValue({
ok: true,
number: 88,
url: 'https://dev.azure.com/acme/Project/_git/orca/pullrequest/88'
})
const provider = getForgeProviderById('azure-devops')
await expect(
provider.createReview?.(
'/repo',
{
provider: 'azure-devops',
base: 'main',
head: 'feature/provider-interface',
title: 'Add provider interface'
},
'ssh-1'
)
).resolves.toEqual({
ok: true,
number: 88,
url: 'https://dev.azure.com/acme/Project/_git/orca/pullrequest/88'
})
expect(createAzureDevOpsPullRequestMock).toHaveBeenCalledWith(
'/repo',
{
provider: 'azure-devops',
base: 'main',
head: 'feature/provider-interface',
title: 'Add provider interface'
},
'ssh-1'
)
})
it('routes Gitea review creation through the shared provider contract', async () => {
createGiteaPullRequestMock.mockResolvedValue({
ok: true,
number: 19,
url: 'https://git.example.com/team/orca/pulls/19'
})
const provider = getForgeProviderById('gitea')
await expect(
provider.createReview?.(
'/repo',
{
provider: 'gitea',
base: 'main',
head: 'feature/provider-interface',
title: 'Add provider interface'
},
'ssh-1'
)
).resolves.toEqual({
ok: true,
number: 19,
url: 'https://git.example.com/team/orca/pulls/19'
})
expect(createGiteaPullRequestMock).toHaveBeenCalledWith(
'/repo',
{
provider: 'gitea',
base: 'main',
head: 'feature/provider-interface',
title: 'Add provider interface'
},
'ssh-1'
)
})
it('adapts GitHub branch lookup through the shared provider contract', async () => {
getPRForBranchMock.mockResolvedValue({
number: 7,
title: 'Provider branch',
state: 'open',
url: 'https://github.com/team/orca/pull/7',
checksStatus: 'success',
updatedAt: '2026-05-29T00:00:00.000Z',
mergeable: 'MERGEABLE'
})
await expect(
getForgeProviderById('github').getReviewForBranch({
repoPath: '/repo',
connectionId: 'ssh-1',
branch: '',
fallbackReviewNumber: 7
})
).resolves.toMatchObject({
provider: 'github',
number: 7,
status: 'success'
})
expect(getPRForBranchMock).toHaveBeenCalledWith('/repo', '', null, 'ssh-1', 7, {
acceptMergedFallbackPR: true
})
})
})