mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 01:57:57 +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.
243 lines
5.7 KiB
TypeScript
243 lines
5.7 KiB
TypeScript
import type {
|
|
GitLabIssueUpdate,
|
|
GitLabMRInlineCommentInput,
|
|
GitLabMRUpdate,
|
|
GitLabProjectRef
|
|
} from '../../shared/gitlab-types'
|
|
import type { Repo } from '../../shared/repo-types'
|
|
import {
|
|
addIssueComment,
|
|
addMRComment,
|
|
addMRInlineComment,
|
|
closeMR,
|
|
createIssue,
|
|
getJobTrace,
|
|
mergeMR,
|
|
reopenMR,
|
|
resolveMRDiscussion,
|
|
retryJob,
|
|
updateIssue,
|
|
updateMR,
|
|
updateMRReviewers
|
|
} from '../gitlab/client'
|
|
import { getRepoRoutingConnectionId } from '../../shared/execution-host'
|
|
|
|
type LocalGitArgs = [] | [{ wslDistro?: string }]
|
|
|
|
export class RuntimeGitLabMutationCommands {
|
|
constructor(
|
|
private readonly deps: {
|
|
resolveRepo: (selector: string) => Promise<Repo>
|
|
getLocalGitArgs: (repo: Repo) => LocalGitArgs
|
|
}
|
|
) {}
|
|
|
|
async createGitLabRepoIssue(repoSelector: string, title: string, body: string) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return createIssue(
|
|
repo.path,
|
|
title,
|
|
body,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async updateGitLabRepoIssue(
|
|
repoSelector: string,
|
|
number: number,
|
|
updates: GitLabIssueUpdate,
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return updateIssue(
|
|
repo.path,
|
|
number,
|
|
updates,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async addGitLabRepoIssueComment(
|
|
repoSelector: string,
|
|
number: number,
|
|
body: string,
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return addIssueComment(
|
|
repo.path,
|
|
number,
|
|
body,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async addGitLabRepoMRComment(
|
|
repoSelector: string,
|
|
iid: number,
|
|
body: string,
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return addMRComment(
|
|
repo.path,
|
|
iid,
|
|
body,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async addGitLabRepoMRInlineComment(
|
|
repoSelector: string,
|
|
iid: number,
|
|
input: GitLabMRInlineCommentInput,
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return addMRInlineComment(
|
|
repo.path,
|
|
iid,
|
|
input,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async resolveGitLabRepoMRDiscussion(
|
|
repoSelector: string,
|
|
iid: number,
|
|
discussionId: string,
|
|
resolved: boolean,
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return resolveMRDiscussion(
|
|
repo.path,
|
|
iid,
|
|
discussionId,
|
|
resolved,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async getGitLabRepoJobTrace(
|
|
repoSelector: string,
|
|
jobId: number,
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return getJobTrace(
|
|
repo.path,
|
|
jobId,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async retryGitLabRepoJob(
|
|
repoSelector: string,
|
|
jobId: number,
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return retryJob(
|
|
repo.path,
|
|
jobId,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async mergeGitLabRepoMR(
|
|
repoSelector: string,
|
|
iid: number,
|
|
method?: 'merge' | 'squash' | 'rebase',
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return mergeMR(
|
|
repo.path,
|
|
iid,
|
|
method ?? 'merge',
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async updateGitLabRepoMRState(
|
|
repoSelector: string,
|
|
iid: number,
|
|
state: 'opened' | 'closed',
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
const updateState = state === 'closed' ? closeMR : reopenMR
|
|
return updateState(
|
|
repo.path,
|
|
iid,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async updateGitLabRepoMR(
|
|
repoSelector: string,
|
|
iid: number,
|
|
updates: GitLabMRUpdate,
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return updateMR(
|
|
repo.path,
|
|
iid,
|
|
updates,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
|
|
async updateGitLabRepoMRReviewers(
|
|
repoSelector: string,
|
|
iid: number,
|
|
reviewerIds: number[],
|
|
projectRef?: GitLabProjectRef | null
|
|
) {
|
|
const repo = await this.deps.resolveRepo(repoSelector)
|
|
return updateMRReviewers(
|
|
repo.path,
|
|
iid,
|
|
reviewerIds,
|
|
repo.issueSourcePreference,
|
|
getRepoRoutingConnectionId(repo),
|
|
projectRef,
|
|
...this.deps.getLocalGitArgs(repo)
|
|
)
|
|
}
|
|
}
|