mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 18:37:24 +00:00
* fix(hooks): approve setup from the ref a new workspace checks out The setup trust check before a create read orca.yaml from the project's own checkout, while the host (since #37977) checks the created worktree. A checkout behind origin/main made every create skip setup and open the "branch has different setup commands" dialog right after creation. The check now reads orca.yaml at the ref the create checks out (the resolved base, or the local branch for explicit reuse), refreshing it only when create would, under one deadline. Any failure falls back to the previous checkout read, and older hosts ignore the new parameter. * fix(hooks): stop optional setup reads at the deadline and cover automation recovery, VM and web paths * fix(hooks): refuse late WSL git retries and approve an automation's saved base on recovery * docs(hooks): move the skipped-setup recovery comment back to its function * fix(automations): re-approve setup when an automation's base branch changes
92 lines
3.0 KiB
TypeScript
92 lines
3.0 KiB
TypeScript
import type { GitAdmissionTier } from '../../../../shared/rpc-contract/source-control/git-admission-tier-params'
|
|
import { gitExecFileAsync } from '../../command-runner/git-exec-file'
|
|
import { isShowRefNoMatchError } from '../../../../shared/git/refs/git-show-ref-no-match'
|
|
import { hasCommitObjectViaGitExec } from '../../refs/resolution/commit-object-ref'
|
|
import { isSafeGitRefName } from '../../../../shared/git/status/git-status-upstream-ref'
|
|
import { resolveWorktreeAddBaseRef } from '../../../../shared/worktree/base-refs/base-ref'
|
|
|
|
type GitExecOptions = {
|
|
wslDistro?: string
|
|
admissionTier?: GitAdmissionTier
|
|
canStart?: () => boolean
|
|
}
|
|
|
|
/** Return the probe's commit OID so callers need not resolve it again. */
|
|
export async function resolveWorktreeBaseCommitOid(
|
|
repoPath: string,
|
|
qualifiedRef: string,
|
|
options: GitExecOptions = {}
|
|
): Promise<string | null> {
|
|
try {
|
|
const { stdout } = await gitExecFileAsync(
|
|
['rev-parse', '--verify', '--quiet', `${qualifiedRef}^{commit}`],
|
|
{
|
|
cwd: repoPath,
|
|
...options
|
|
}
|
|
)
|
|
const oid = stdout.trim()
|
|
return oid.length > 0 ? oid : null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export async function hasWorktreeBaseCommitRef(
|
|
repoPath: string,
|
|
qualifiedRef: string,
|
|
options: GitExecOptions = {}
|
|
): Promise<boolean> {
|
|
return (await resolveWorktreeBaseCommitOid(repoPath, qualifiedRef, options)) !== null
|
|
}
|
|
|
|
/** Compare resolved qualified refs so aliases such as main and refs/heads/main share one base. */
|
|
export function resolveLocalWorktreeBaseRef(
|
|
repoPath: string,
|
|
baseRef: string,
|
|
options: GitExecOptions = {}
|
|
): Promise<string> {
|
|
return resolveWorktreeAddBaseRef(baseRef, (qualifiedRef) =>
|
|
hasWorktreeBaseCommitRef(repoPath, qualifiedRef, options)
|
|
)
|
|
}
|
|
|
|
/** Creation and prefetch share this presence check so they agree on reusable local bases. */
|
|
export async function hasLocalWorktreeBaseRef(
|
|
repoPath: string,
|
|
baseRef: string,
|
|
options: GitExecOptions = {}
|
|
): Promise<boolean> {
|
|
const refExists = (qualifiedRef: string) =>
|
|
hasWorktreeBaseCommitRef(repoPath, qualifiedRef, options)
|
|
const resolvedBaseRef = await resolveWorktreeAddBaseRef(baseRef, refExists)
|
|
if (resolvedBaseRef !== baseRef) {
|
|
return true
|
|
}
|
|
if (baseRef.startsWith('refs/')) {
|
|
return refExists(baseRef)
|
|
}
|
|
return hasCommitObjectViaGitExec(
|
|
(gitArgs) => gitExecFileAsync(gitArgs, { cwd: repoPath, ...options }),
|
|
baseRef
|
|
)
|
|
}
|
|
|
|
export type WorktreeBaseRefPresence = 'present' | 'absent' | 'unknown'
|
|
|
|
/** Exact ref probes preserve unknown on execution failure; inject the runner to support relay hosts too. */
|
|
export async function probeWorktreeBaseRefPresence(
|
|
runGit: (args: string[]) => Promise<{ stdout: string }>,
|
|
qualifiedRef: string
|
|
): Promise<WorktreeBaseRefPresence> {
|
|
if (!isSafeGitRefName(qualifiedRef)) {
|
|
return 'unknown'
|
|
}
|
|
try {
|
|
await runGit(['show-ref', '--verify', '--quiet', '--', qualifiedRef])
|
|
return 'present'
|
|
} catch (error) {
|
|
return isShowRefNoMatchError(error) ? 'absent' : 'unknown'
|
|
}
|
|
}
|