Merge pull request #3684 from deepseek-harness/turtle/custom-review-ownership

chore: automate changed-file review ownership
This commit is contained in:
Turtle
2026-09-08 13:47:15 +08:00
committed by GitHub
14 changed files with 982 additions and 0 deletions
+41
View File
@@ -774,6 +774,47 @@ describe('Python release workflows', () => {
})
})
describe('Request review workflow', () => {
it('runs trusted routing on reviewable pull request updates', () => {
const workflow = loadWorkflow('.github/workflows/request-review.yml')
const event = workflowEvent(workflow, 'pull_request_target')
const job = workflowJob(workflow, 'request-review')
if (!isRecord(workflow.on)) throw new TypeError('request-review workflow must define events')
if (!Array.isArray(job.steps)) throw new TypeError('request-review job must define steps')
const steps = job.steps.filter(isRecord)
const checkout = steps.find(step => step.name === 'Check out trusted review policy')
const request = steps.find(step => step.name === 'Request reviewers')
expect(workflow.name).toBe('request-review')
expect(Object.keys(workflow.on)).toEqual(['pull_request_target'])
expect(event.types).toEqual(['opened', 'synchronize', 'reopened', 'ready_for_review'])
expect(workflow.permissions).toEqual({ contents: 'read', 'pull-requests': 'write' })
expect(workflow.concurrency).toEqual({
group: 'request-review-${{ github.event.pull_request.number }}',
'cancel-in-progress': true,
})
expect(job).toMatchObject({
name: 'request-review',
if: '${{ !github.event.pull_request.draft }}',
'runs-on': 'ubuntu-latest',
'timeout-minutes': 5,
})
expect(checkout).toMatchObject({
uses: 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1',
with: {
ref: '${{ github.event.repository.default_branch }}',
'persist-credentials': false,
},
})
expect(request).toMatchObject({
env: { GITHUB_TOKEN: '${{ github.token }}' },
run: 'node .github/review-ownership/request-review.mjs',
})
expect(JSON.stringify(workflow)).not.toContain('github.event.pull_request.head')
expect(JSON.stringify(workflow)).not.toContain('secrets.')
})
})
describe('Issue lifecycle workflow', () => {
it('runs the lifecycle job on every PR/review event but gates token and board steps', () => {
const lifecycle = loadWorkflow('.github/workflows/issue-lifecycle.yml')
+9
View File
@@ -240,6 +240,15 @@ describe('gate graph validation', () => {
},
)
it.each(['ci-primary', 'ci-static', 'check-all'] as const)(
'keeps review request policy tests in %s',
(mode) => {
const ids = withPnpmEntrypoint(() => gatesForMode(mode).map(subject => subject.id))
expect(ids).toContain('request-review')
},
)
it.each(['ci-primary', 'ci-static', 'check-all', 'hygiene'] as const)(
'keeps hard-coded Client UI copy enforcement in %s',
(mode) => {
+2
View File
@@ -267,6 +267,7 @@ export function gatesForMode(selected: Mode): Gate[] {
pnpmScript('client-domain-graph', 'verify-client-domain-graph', { label: 'client domain graph' }),
pnpmScript('test', 'test'),
pnpmScript('issue-management', 'test:issue-management', { label: 'Issue management policy' }),
pnpmScript('request-review', 'test:request-review', { label: 'Review request policy' }),
pnpmScript('duplication', 'duplication'),
snapshotGate(),
expectedOutputGate(),
@@ -310,6 +311,7 @@ function ciSharedStaticGates(): Gate[] {
pnpmScript('client-ui-i18n', 'verify-client-ui-i18n', { label: 'client UI i18n' }),
pnpmScript('no-bare-dispatcher', 'verify-no-bare-dispatcher', { label: 'proxy-aware dispatchers' }),
pnpmScript('issue-management', 'test:issue-management', { label: 'Issue management policy' }),
pnpmScript('request-review', 'test:request-review', { label: 'Review request policy' }),
]
}