refactor(github): organize concrete feature owners (#41601)

This commit is contained in:
Neil
2026-11-12 09:17:26 -08:00
committed by GitHub
parent ff9fd6634b
commit fb8d6f950b
1003 changed files with 4460 additions and 8422 deletions
@@ -1,11 +1,11 @@
import type { GlobalSettings } from '../global-settings-types'
import type { GlobalSettings } from '../../global-settings-types'
import {
LOCAL_EXECUTION_HOST_ID,
normalizeExecutionHostId,
toSshExecutionHostId,
type ExecutionHostId
} from '../execution-host'
import { taskSourceCacheScopeHostId } from '../work-items/task-source-context'
} from '../../execution-host'
import { taskSourceCacheScopeHostId } from '../../work-items/task-source-context'
export type RuntimeFocusSettings =
| Pick<GlobalSettings, 'activeRuntimeEnvironmentId'>
@@ -1,7 +1,7 @@
import type { PRCheckDetail } from './check-types'
import type { CheckStatus } from './pull-request-types'
import type { HostedReviewState } from '../source-control/hosted-review/hosted-review-contracts'
import { reviewRefreshIntervalMs } from '../review-refresh-policy'
import type { CheckStatus } from '../pull-requests/pull-request-types'
import type { HostedReviewState } from '../../source-control/hosted-review/hosted-review-contracts'
import { reviewRefreshIntervalMs } from '../../review-refresh-policy'
export function detailedChecksStatus(checks: readonly PRCheckDetail[]): CheckStatus | undefined {
if (checks.length === 0) {
@@ -1,9 +1,5 @@
import { expect, it } from 'vitest'
import {
acceptPRCheckObservation,
isCompletePRCheckOwner,
projectPRCheckOwner
} from './complete-pr-check-owner'
import { acceptPRCheckObservation } from './complete-pr-check-owner'
const summary = {
state: 'success' as const,
@@ -49,17 +45,3 @@ it('retains last-good only for the same proved source, target and nonempty head'
acceptPRCheckObservation({ ...pr, checksSummary: undefined }, pr, context)?.checksSummary
).toBeUndefined()
})
it('carries unavailable authority explicitly through display and review projections without lending it to another head', () => {
const unavailable = acceptPRCheckObservation({ ...pr, checksSummary: undefined }, null, context)!
const display = projectPRCheckOwner(unavailable, { ...unavailable })
expect(isCompletePRCheckOwner(display)).toBe(true)
const review = projectPRCheckOwner(display, { ...display, status: display.checksStatus })
expect(isCompletePRCheckOwner(review)).toBe(true)
expect(isCompletePRCheckOwner({ ...review })).toBe(false)
expect(isCompletePRCheckOwner(projectPRCheckOwner(review, { ...review, headSha: 'h2' }))).toBe(
false
)
const full = acceptPRCheckObservation(pr, null, context)!
expect(isCompletePRCheckOwner({ ...pr, checksSummary: full.checksSummary })).toBe(false)
})
@@ -1,6 +1,10 @@
import type { CheckStatus, GitHubOwnerRepo, ProviderCheckSummary } from './pull-request-types'
import { githubRepoIdentityKey } from './repository-identity-key'
import { matchesGitHubWorkItemTarget, parseGitHubItemRepository } from './work-item-target'
import type { CheckStatus, ProviderCheckSummary } from '../pull-requests/pull-request-types'
import type { GitHubRepositoryIdentity as GitHubOwnerRepo } from '../repositories/repository-identity'
import { githubRepoIdentityKey } from '../repositories/repository-identity-key'
import {
matchesGitHubWorkItemTarget,
parseGitHubItemRepository
} from '../work-items/work-item-target'
type CheckOwner = {
number?: number
@@ -1,4 +1,4 @@
import type { GitHubRepositoryIdentity } from './pull-request-types'
import type { GitHubRepositoryIdentity } from '../repositories/repository-identity'
export type GitHubReactionContent =
| '+1'
@@ -1,5 +1,8 @@
import type { Repo } from '../repo-types'
import { githubHostFromIdentityKey, repoUpstreamIdentityKey } from './repository-identity-key'
import type { Repo } from '../../repo-types'
import {
githubHostFromIdentityKey,
repoUpstreamIdentityKey
} from '../repositories/repository-identity-key'
export type GitHubRepoReference = {
owner: string
@@ -1,18 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
GITHUB_PROJECT_REF_INPUT_MAX_BYTES,
hasBoundedGitHubProjectRefInputText,
isGitHubProjectRefInputTooLarge
} from './project-ref-input'
describe('GitHub project reference input limits', () => {
it('rejects oversized whitespace before submit checks trim the reference', () => {
const oversizedWhitespace = ' '.repeat(GITHUB_PROJECT_REF_INPUT_MAX_BYTES + 1)
expect(isGitHubProjectRefInputTooLarge(oversizedWhitespace)).toBe(true)
expect(hasBoundedGitHubProjectRefInputText(oversizedWhitespace)).toBe(false)
expect(hasBoundedGitHubProjectRefInputText(' acme/42 ')).toBe(true)
expect(hasBoundedGitHubProjectRefInputText(' ')).toBe(false)
})
})
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { githubProjectHost, githubProjectIdentityKey } from './project-identity'
import { githubProjectIdentityKey } from './project-identity'
describe('GitHub project identity', () => {
it('keeps legacy github.com keys while isolating Enterprise hosts and ports', () => {
@@ -14,9 +14,4 @@ describe('GitHub project identity', () => {
'ghe.example:8443:organization:acme:7'
)
})
it('pins host-less projects to github.com', () => {
expect(githubProjectHost()).toBe('github.com')
expect(githubProjectHost('ghe.example:8443')).toBe('ghe.example:8443')
})
})
@@ -1,4 +1,4 @@
import { isDefaultGitHubHost } from './repository-identity-key'
import { isDefaultGitHubHost } from '../repositories/repository-identity-key'
export type GitHubProjectIdentity = {
owner: string
@@ -1,4 +1,4 @@
import { isClipboardTextByteLengthOverLimit } from '../clipboard-text'
import { isClipboardTextByteLengthOverLimit } from '../../clipboard-text'
export const GITHUB_PROJECT_REF_INPUT_MAX_BYTES = 2 * 1024
export const GITHUB_PROJECT_REF_INPUT_TOO_LARGE_ERROR = 'Project reference is too large to resolve.'
@@ -1,6 +1,6 @@
// Keep Project request payloads separate from ProjectV2 domain shapes so renderer domain imports do not pull IPC arguments.
import type { GitHubProjectFieldMutationValue, GitHubProjectOwnerType } from './project-types'
import type { GitHubIssueUpdate } from '../issue-mutation-types'
import type { GitHubIssueUpdate } from '../../issue-mutation-types'
/** Set by a click: it may start the stopped WSL distro gh lives in (E9). Loads that also run
* unprompted (mount effects, restore) leave it unset. Local IPC only. */
@@ -1,5 +1,5 @@
// Project IPC envelopes share classified failures and cross-module work-item/comment/user types unnecessary in the ProjectV2 domain model.
import type { PRComment } from './comment-types'
import type { PRComment } from '../comments/comment-types'
import type {
GitHubIssueType,
GitHubProjectOwnerType,
@@ -7,8 +7,8 @@ import type {
GitHubProjectTable,
GitHubProjectViewSummary
} from './project-types'
import type { GitHubAssignableUser } from './pull-request-types'
import type { GitHubWorkItemDetails } from './work-item-types'
import type { GitHubAssignableUser } from '../pull-requests/pull-request-types'
import type { GitHubWorkItemDetails } from '../work-items/work-item-types'
export type GitHubProjectViewErrorType =
| 'auth_required'
@@ -1,4 +1,4 @@
import type { PRMergeableState, PRReviewDecision, PRState } from './pull-request-types'
import type { PRMergeableState, PRReviewDecision, PRState } from '../pull-request-types'
export type GitHubPRAutoMergeAvailabilityInput = {
state: PRState
@@ -5,13 +5,6 @@ import {
} from './pull-request-merge-methods'
describe('GitHub PR merge methods', () => {
it('keeps the historical squash-first fallback when repository metadata is missing', () => {
expect(resolveGitHubPRMergeMethods()).toEqual({
defaultMethod: 'squash',
methods: ['squash', 'merge', 'rebase']
})
})
it('uses GitHub viewer defaults and hides methods disabled by the repository', () => {
const settings = normalizeGitHubPRMergeMethodSettings({
defaultMethod: 'REBASE',
@@ -1,4 +1,4 @@
import type { GitHubPRMergeMethod, GitHubPRMergeMethodSettings } from './pull-request-types'
import type { GitHubPRMergeMethod, GitHubPRMergeMethodSettings } from '../pull-request-types'
export const GITHUB_PR_MERGE_METHODS = ['squash', 'merge', 'rebase'] as const
@@ -1,5 +1,5 @@
import { getProviderChecksOutcome } from '../source-control/checks/provider-check-summary'
import type { CheckStatus, ProviderCheckSummary } from './pull-request-types'
import { getProviderChecksOutcome } from '../../../source-control/checks/provider-check-summary'
import type { CheckStatus, ProviderCheckSummary } from '../pull-request-types'
import {
canShowGitHubPRAutoMergeControl,
type GitHubPRAutoMergeAvailabilityInput
@@ -1,4 +1,4 @@
import type { GitHubPRStack, GitHubPRStackEntry } from './pull-request-types'
import type { GitHubPRStack, GitHubPRStackEntry } from '../pull-request-types'
export type GitHubPRStackMergeScope = {
count: number
@@ -1,6 +1,6 @@
import type { GitHubAssignableUser } from './pull-request-types'
import type { GitHubWorkItem } from './work-item-types'
import { isClipboardTextByteLengthOverLimit } from '../clipboard-text'
import type { GitHubWorkItem } from '../work-items/work-item-types'
import { isClipboardTextByteLengthOverLimit } from '../../clipboard-text'
type ReviewDisplayItem = Pick<GitHubWorkItem, 'reviewDecision' | 'reviewRequests' | 'latestReviews'>
export type GitHubPRPrimaryReviewer = Pick<GitHubAssignableUser, 'login' | 'avatarUrl'> & {
@@ -1,8 +1,13 @@
import type { GitHubRepositoryIdentity } from '../repositories/repository-identity'
export type PRState = 'open' | 'closed' | 'merged' | 'draft'
export type IssueState = 'open' | 'closed'
export type CheckStatus = 'pending' | 'success' | 'failure' | 'neutral'
export type PRMergeableState = 'MERGEABLE' | 'CONFLICTING' | 'UNKNOWN'
export type PRReviewDecision = 'APPROVED' | 'CHANGES_REQUESTED' | 'REVIEW_REQUIRED'
export type PRConflictSummary = {
@@ -13,9 +18,6 @@ export type PRConflictSummary = {
localMergeState?: 'clean'
}
// Keep GHES host identity across renderer/RPC boundaries to prevent actions targeting same-named github.com repos.
export type GitHubRepositoryIdentity = { owner: string; repo: string; host?: string }
export type GitHubPRMergeMethod = 'merge' | 'squash' | 'rebase'
export type GitHubPRMergeMethodSettings = {
@@ -150,6 +152,3 @@ export type GitHubPRFileContents = {
originalTooLarge?: boolean
modifiedTooLarge?: boolean
}
// Share the identity shape across IPC/renderer without main imports; main’s gh-utils.ts retains the OwnerRepo alias.
export type GitHubOwnerRepo = GitHubRepositoryIdentity
@@ -1,5 +1,5 @@
import type { PRInfo } from './pull-request-types'
import type { Worktree } from '../worktree/types'
import type { PRInfo } from '../pull-request-types'
import type { Worktree } from '../../../worktree/types'
export function shouldClearDivergedLinkedMergedPR(args: {
pr: PRInfo | null
@@ -1,4 +1,4 @@
import type { PRInfo } from './pull-request-types'
import type { PRInfo } from '../pull-request-types'
import type { GitHubPRRefreshCandidate } from './pull-request-refresh-types'
export type PRBranchFallback = {
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest'
import type { PRInfo } from './pull-request-types'
import type { PRInfo } from '../pull-request-types'
import { normalizeGitHubPRForBranchOutcome } from './pull-request-for-branch-outcome'
const PR: PRInfo = {
@@ -14,13 +14,6 @@ const PR: PRInfo = {
}
describe('normalizeGitHubPRForBranchOutcome', () => {
it.each([
{ kind: 'no-pr' as const, fetchedAt: 10 },
{ kind: 'no-pr' as const, fetchedAt: 10, rejectedPRUrls: [PR.url] }
])('preserves no-PR responses from older and newer hosts', (outcome) => {
expect(normalizeGitHubPRForBranchOutcome(outcome, 20)).toEqual(outcome)
})
it('normalizes legacy PRInfo and null responses', () => {
expect(normalizeGitHubPRForBranchOutcome(PR, 20)).toEqual({
kind: 'found',
@@ -1,5 +1,5 @@
import type { PRRefreshOutcome } from './pull-request-refresh-types'
import type { PRInfo } from './pull-request-types'
import type { PRInfo } from '../pull-request-types'
export type GitHubPRForBranchResponse = PRRefreshOutcome | PRInfo | null
@@ -1,5 +1,5 @@
import type { RepoKind } from '../repo-types'
import type { CheckStatus, PRInfo, PRMergeableState, PRState } from './pull-request-types'
import type { RepoKind } from '../../../repo-types'
import type { CheckStatus, PRInfo, PRMergeableState, PRState } from '../pull-request-types'
/** Classified failures drive stable empty-state copy. Auth/permission/repo_unavailable/gh_unavailable make existing-review lookup impossible and must hide Create. */
export type PRRefreshErrorType =
@@ -12,9 +12,6 @@ export type PRRefreshErrorType =
| 'server_error'
| 'unknown'
// Backward-compatible name used by outage-copy consumers added on main.
export type PRRefreshUpstreamErrorType = PRRefreshErrorType
export type PRRefreshOutcome =
| { kind: 'found'; pr: PRInfo; fetchedAt: number }
| { kind: 'no-pr'; fetchedAt: number; rejectedPRUrls?: string[] }
@@ -1,4 +1,4 @@
import type { Repo } from '../repo-types'
import type { Repo } from '../../repo-types'
// Share github.com/GHES detection across cache identity, quota scoping and execution routing.
export function isDefaultGitHubHost(host?: string): boolean {
@@ -0,0 +1,2 @@
// Keep GHES host identity across renderer/RPC boundaries to prevent actions targeting same-named github.com repos.
export type GitHubRepositoryIdentity = { owner: string; repo: string; host?: string }
@@ -1,6 +1,6 @@
import { z } from 'zod'
import { SlugRepo } from '../rpc-contract/github-repo-target-params'
import { ExpectedRuntimeSourceSchema } from '../runtime-rpc-envelope'
import { SlugRepo } from '../../rpc-contract/github-repo-target-params'
import { ExpectedRuntimeSourceSchema } from '../../runtime-rpc-envelope'
const methods = new Set([
'github.workItemDetails',
@@ -1,4 +1,4 @@
import type { ClassifiedError } from '../classified-error'
import type { ClassifiedError } from '../../classified-error'
import { GITHUB_SEARCH_RESULT_WINDOW_ERROR_PATTERN } from './work-items-query-bounds'
export function getWorkItemPageErrorTypes(errors: unknown): ClassifiedError['type'][] {
@@ -1,6 +1,6 @@
import type { GitHubOwnerRepo } from './pull-request-types'
import type { GitHubRepositoryIdentity as GitHubOwnerRepo } from '../repositories/repository-identity'
import type { GitHubWorkItem, GitHubWorkItemDetails } from './work-item-types'
import { githubRepoIdentityKey } from './repository-identity-key'
import { githubRepoIdentityKey } from '../repositories/repository-identity-key'
export type GitHubWorkItemTarget = {
repository: GitHubOwnerRepo
@@ -1,18 +1,20 @@
import type { ClassifiedError } from '../classified-error'
import type { ExecutionHostId } from '../execution-host'
import type { PRCheckDetail } from './check-types'
import type { GitHubIssueTimelineItem, PRComment } from './comment-types'
import type { ClassifiedError } from '../../classified-error'
import type { ExecutionHostId } from '../../execution-host'
import type { PRCheckDetail } from '../checks/check-types'
import type { GitHubIssueTimelineItem, PRComment } from '../comments/comment-types'
import type {
GitHubAssignableUser,
GitHubOwnerRepo,
GitHubPRFile,
GitHubPRMergeMethodSettings,
GitHubPRReviewSummary,
GitHubRepositoryIdentity,
PRMergeableState,
PRReviewDecision,
ProviderCheckSummary
} from './pull-request-types'
} from '../pull-requests/pull-request-types'
import type {
GitHubRepositoryIdentity as GitHubOwnerRepo,
GitHubRepositoryIdentity
} from '../repositories/repository-identity'
export type GitHubWorkItem = {
id: string
@@ -1,4 +1,4 @@
import { isClipboardTextByteLengthOverLimit } from '../clipboard-text'
import { isClipboardTextByteLengthOverLimit } from '../../clipboard-text'
export const GITHUB_WORK_ITEMS_QUERY_MAX_BYTES = 8 * 1024