mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 18:17:36 +00:00
* feat(ci): ratchet raw repo connectionId host reads; one drop-in resolver Codex review 6 class fix (#4/#6/#7): host decisions read off a repo row's legacy connectionId miss rows that name SSH only as executionHostId. - getRepoRoutingConnectionId (shared/execution-host.ts): drop-in for a raw repo.connectionId routing check that also finds executionHostId-only SSH. - check-repo-host-read-ratchet: per-file count of raw repo connectionId reads in src/main, src/shared, src/cli; counts may only shrink. - Migrated 66 cheap reads: runtime GitHub/GitLab commands, PR/MR head ref fetches, preserved-branch cleanup, ref queries, base-ref IPC, worktree preparation, trash sweep, scan cache TTL, usage metadata. * fix(ipc): PR base IPC routes executionHostId-only SSH rows; ratchet is a stated lower bound Review follow-up (Opus on #31096): - worktrees:resolvePrBase decided git/gh routing on the raw connectionId while its head-ref fetches already used the resolver; one resolved connectionId now drives all of it (test fails on main). - getRepoRoutingConnectionId's contract is stated exactly: never local when the raw field is set; on a contradictory ssh row executionHostId wins. - The ratchet regex no longer matches report.connectionId; header and docs say it is a lower bound. - Regression tests for a runtime GitHub and GitLab command site. * test(ci): pin the repo host-read ratchet step to the static phase * fix(ci): repo host-read ratchet skips verbatim field copies into projected rows A copy of connectionId into a projected row decides nothing; migrating it to the resolver would change what the projection publishes. The sidebar feed catalog's copy (added after the baseline) and two older projections no longer count; baseline pruned to 91.
237 lines
6.5 KiB
TypeScript
237 lines
6.5 KiB
TypeScript
import type { GitHubOwnerRepo } from '../../shared/github/pull-request-types'
|
|
import type { GitHubPullRequestStateUpdate } from '../../shared/issue-mutation-types'
|
|
import type { GitHubReactionContent } from '../../shared/github/comment-types'
|
|
import type { Repo } from '../../shared/repo-types'
|
|
import type { LocalProjectGhExecOptions } from '../project-runtime-git-options'
|
|
import {
|
|
mergePR,
|
|
markPRReadyForReview,
|
|
removePRReviewers,
|
|
requestPRReviewers,
|
|
rerunPRChecks,
|
|
resolveReviewThread,
|
|
setPRAutoMerge,
|
|
setPRCommentReaction,
|
|
setPRFileViewed,
|
|
updatePRDetails,
|
|
updatePRState,
|
|
updatePRTitle
|
|
} from '../github/client'
|
|
import { getRepoRoutingConnectionId } from '../../shared/execution-host'
|
|
|
|
type LocalGitArgs = [] | [LocalProjectGhExecOptions]
|
|
|
|
type RuntimeGitHubReviewMutationCommandsDeps = {
|
|
resolveRepo: (selector: string) => Promise<Repo>
|
|
getLocalGitArgs: (repo: Repo) => LocalGitArgs
|
|
}
|
|
|
|
export class RuntimeGitHubReviewMutationCommands {
|
|
constructor(private readonly deps: RuntimeGitHubReviewMutationCommandsDeps) {}
|
|
|
|
async rerunRepoPRChecks(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
options?: { headSha?: string; failedOnly?: boolean; prRepo?: GitHubOwnerRepo | null }
|
|
): Promise<Awaited<ReturnType<typeof rerunPRChecks>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return rerunPRChecks(
|
|
repo.path,
|
|
prNumber,
|
|
options,
|
|
getRepoRoutingConnectionId(repo),
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async setRepoPRCommentReaction(
|
|
repoSelector: string,
|
|
reactionSubjectId: string,
|
|
content: GitHubReactionContent,
|
|
reacted: boolean,
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof setPRCommentReaction>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return setPRCommentReaction(
|
|
repo.path,
|
|
reactionSubjectId,
|
|
content,
|
|
reacted,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async resolveRepoReviewThread(
|
|
repoSelector: string,
|
|
threadId: string,
|
|
resolve: boolean,
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof resolveReviewThread>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return resolveReviewThread(
|
|
repo.path,
|
|
threadId,
|
|
resolve,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async setRepoPRFileViewed(
|
|
repoSelector: string,
|
|
args: {
|
|
prRepo?: GitHubOwnerRepo | null
|
|
pullRequestId: string
|
|
path: string
|
|
viewed: boolean
|
|
}
|
|
): Promise<Awaited<ReturnType<typeof setPRFileViewed>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return setPRFileViewed({
|
|
repoPath: repo.path,
|
|
connectionId: getRepoRoutingConnectionId(repo),
|
|
localGitOptions: this.deps.getLocalGitArgs(repo)[0],
|
|
...args
|
|
})
|
|
}
|
|
|
|
async updateRepoPRTitle(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
title: string,
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof updatePRTitle>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return updatePRTitle(
|
|
repo.path,
|
|
prNumber,
|
|
title,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async updateRepoPRDetails(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
updates: { title?: string; body?: string },
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof updatePRDetails>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return updatePRDetails(
|
|
repo.path,
|
|
prNumber,
|
|
updates,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async mergeRepoPR(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
method?: 'merge' | 'squash' | 'rebase',
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof mergePR>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return mergePR(
|
|
repo.path,
|
|
prNumber,
|
|
method,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async setRepoPRAutoMerge(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
enabled: boolean,
|
|
method?: 'merge' | 'squash' | 'rebase',
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof setPRAutoMerge>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return setPRAutoMerge(
|
|
repo.path,
|
|
prNumber,
|
|
enabled,
|
|
method,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async markRepoPRReadyForReview(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof markPRReadyForReview>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return markPRReadyForReview(
|
|
repo.path,
|
|
prNumber,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async updateRepoPRState(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
updates: GitHubPullRequestStateUpdate,
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof updatePRState>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return updatePRState(
|
|
repo.path,
|
|
prNumber,
|
|
updates,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async requestRepoPRReviewers(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
reviewers: string[],
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof requestPRReviewers>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return requestPRReviewers(
|
|
repo.path,
|
|
prNumber,
|
|
reviewers,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async removeRepoPRReviewers(
|
|
repoSelector: string,
|
|
prNumber: number,
|
|
reviewers: string[],
|
|
prRepo?: GitHubOwnerRepo | null
|
|
): Promise<Awaited<ReturnType<typeof removePRReviewers>>> {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return removePRReviewers(
|
|
repo.path,
|
|
prNumber,
|
|
reviewers,
|
|
getRepoRoutingConnectionId(repo),
|
|
prRepo ?? null,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
}
|