mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-11-09 20:07:43 +08:00
fix(ci): keep the pre-merge check green in report mode (#7311)
* fix(ci): keep the pre-merge check off the report-mode failures * fix(ci): fail the pre-merge check in block mode without a base commit * fix(ci): report every pre-merge failure the way its mode asks The merge step now separates a base commit it cannot fetch from a merge it cannot do, both failures print an annotation, and a spec pins the mode wiring of the three Policy workflows. * test(ci): type the Policy workflow assertions --------- Co-authored-by: imccyu <imccyu@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
imccyu
parent
ae38375654
commit
df469ea6ff
+1
-1
@@ -4,6 +4,6 @@ Run jobs on Windows runners (`windows-*` labels) under native `pwsh`. Native Win
|
||||
|
||||
The manual [Windows packaging workflow](workflows/windows-package.yml) uses the dedicated self-hosted Windows x64 label `dsh-win-package-trial` under native `pwsh`; preserve this routing separately from the automatic CI lanes.
|
||||
|
||||
The merge checks run from three workflows named `Policy`, which run on `pull_request_target` so their definitions come from master, and call the `deepseek-harness-check` action directly: `pr-check-on-head-branch.yml` on pull-request updates gives `Policy / Master Change` and `Policy / Pre-Merge Check`, `pr-check-after-approve.yml` on pull-request updates and submitted or dismissed reviews gives `Policy / Approve Check` and `Policy / Reviewer Evaluate`, and `pr-check-on-base-branch.yml` on master pushes re-runs the head-branch checks as `Policy / Recheck`. Branch rules require those check names, so keep the job names and the workflow name. Each check reads its mode from a repository variable: `MERGE_POLICY_MASTER_DIFF`, `MERGE_POLICY_PRE_MERGE`, `MERGE_POLICY_HEAD_DIFF`, and `MERGE_POLICY_REVIEW`, each `off` (skip), `report` (run without failing the job), or `block` (fail the job); a missing value or an unknown one counts as `report`. `Policy / Pre-Merge Check` merges the commit `Policy / Master Change` reports, so it runs only after that job and stays off while `MERGE_POLICY_MASTER_DIFF` is `off`.
|
||||
The merge checks run from three workflows named `Policy`, which run on `pull_request_target` so their definitions come from master, and call the `deepseek-harness-check` action directly: `pr-check-on-head-branch.yml` on pull-request updates gives `Policy / Master Change` and `Policy / Pre-Merge Check`, `pr-check-after-approve.yml` on pull-request updates and submitted or dismissed reviews gives `Policy / Approve Check` and `Policy / Reviewer Evaluate`, and `pr-check-on-base-branch.yml` on master pushes re-runs the head-branch checks as `Policy / Recheck`. Branch rules require those check names, so keep the job names and the workflow name. Each check reads its mode from a repository variable: `MERGE_POLICY_MASTER_DIFF`, `MERGE_POLICY_PRE_MERGE`, `MERGE_POLICY_HEAD_DIFF`, and `MERGE_POLICY_REVIEW`, each `off` (skip), `report` (run without failing the job), or `block` (fail the job); a missing value or an unknown one counts as `report`. `Policy / Pre-Merge Check` merges the commit `Policy / Master Change` reports, so it runs only after that job and stays off while `MERGE_POLICY_MASTER_DIFF` is `off`; a merge it cannot do and a build that fails both follow its own mode, so `report` warns and skips the build while `block` fails the job.
|
||||
|
||||
The manual Desktop publication workflow selects a successful package run and attempt, then routes each retained build through `DESKTOP_PUBLISH_RUNNERS` to its original machine's unique label. Keep Windows run steps on native PowerShell and Mac run steps on the default POSIX shell; shared entrypoints are Node scripts. Test and production jobs use separate `desktop-test` and `desktop-production` approval Environments after a credential-free preparation job.
|
||||
|
||||
@@ -57,28 +57,51 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Merge the checked base-branch commit
|
||||
# Merging is the precondition of the build below, so a failure here warns and skips it in `report` mode and fails
|
||||
# in `block` mode.
|
||||
- id: merge
|
||||
name: Merge the checked base-branch commit
|
||||
env:
|
||||
CHECK_MODE: ${{ vars.MERGE_POLICY_PRE_MERGE }}
|
||||
BASE_SHA: ${{ needs.master.outputs.base_sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
SINCE: ${{ needs.master.outputs.since }}
|
||||
run: |
|
||||
[[ "$BASE_SHA" =~ ^[0-9a-f]{40}$ && "$SINCE" =~ ^[0-9]+$ ]] || { echo "::error::the master diff check reported no base commit"; exit 1; }
|
||||
git fetch --no-tags --no-write-fetch-head --shallow-since="$SINCE" origin "$HEAD_SHA" "$BASE_SHA"
|
||||
git -c user.name=pr-check -c user.email=pr-check@users.noreply.github.com merge --no-ff --no-edit -m "Merge $BASE_SHA into $HEAD_SHA" "$BASE_SHA"
|
||||
stop() {
|
||||
if [ "$CHECK_MODE" = block ]; then
|
||||
echo "::error title=Pre-Merge Check::$1"
|
||||
exit 1
|
||||
fi
|
||||
echo "::warning title=Pre-Merge Check::$1"
|
||||
exit 0
|
||||
}
|
||||
if [[ ! "$BASE_SHA" =~ ^[0-9a-f]{40}$ || ! "$SINCE" =~ ^[0-9]+$ ]]; then
|
||||
stop "the master diff check reported no base commit, so nothing was merged or compiled"
|
||||
fi
|
||||
git fetch --no-tags --no-write-fetch-head --shallow-since="$SINCE" origin "$HEAD_SHA" "$BASE_SHA" ||
|
||||
stop "the base commit $BASE_SHA could not be fetched, so nothing was merged or compiled"
|
||||
git -c user.name=pr-check -c user.email=pr-check@users.noreply.github.com merge --no-ff --no-edit -m "Merge $BASE_SHA into $HEAD_SHA" "$BASE_SHA" ||
|
||||
stop "the pull request cannot merge $BASE_SHA; merge master into it and push, then this check runs again"
|
||||
echo "merged=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- uses: pnpm/action-setup@v5.0.0
|
||||
if: steps.merge.outputs.merged == 'true'
|
||||
|
||||
- uses: actions/setup-node@v7.0.0
|
||||
if: steps.merge.outputs.merged == 'true'
|
||||
with:
|
||||
node-version: '24'
|
||||
package-manager-cache: false
|
||||
|
||||
- name: Run the pre-merge command
|
||||
if: steps.merge.outputs.merged == 'true'
|
||||
env:
|
||||
CHECK_MODE: ${{ vars.MERGE_POLICY_PRE_MERGE }}
|
||||
run: |
|
||||
if ! bash -euxo pipefail -c 'pnpm install --frozen-lockfile && pnpm exec tsx scripts/compile-referenced-projects.ts host-contracts && pnpm exec tsx scripts/compile-referenced-projects.ts client'; then
|
||||
if [ "$CHECK_MODE" = block ]; then exit 1; fi
|
||||
if [ "$CHECK_MODE" = block ]; then
|
||||
echo "::error title=Pre-Merge Check::the merged tree does not install or compile"
|
||||
exit 1
|
||||
fi
|
||||
echo "::warning title=Pre-Merge Check::the merged tree does not install or compile; this check does not block"
|
||||
fi
|
||||
|
||||
@@ -1686,3 +1686,49 @@ function workflowJob(workflow: Record<string, unknown>, job: string): Record<str
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
}
|
||||
|
||||
describe('Policy workflows', () => {
|
||||
const workflows = [
|
||||
['pr-check-on-head-branch.yml', ['master']],
|
||||
['pr-check-after-approve.yml', ['approve', 'review']],
|
||||
] as const
|
||||
|
||||
function stepsOf(job: Record<string, unknown>): Record<string, unknown>[] {
|
||||
const steps = job.steps as unknown[]
|
||||
if (!Array.isArray(steps)) throw new TypeError('job must define steps')
|
||||
return steps.filter(isRecord)
|
||||
}
|
||||
|
||||
it.each(workflows)('%s runs each check from master and reads its mode from a repository variable', (file, jobs) => {
|
||||
const workflow = loadWorkflow('.github/workflows/' + file)
|
||||
expect(Object.keys(workflow).filter(key => key !== 'name')).toEqual(['on', 'permissions', 'concurrency', 'jobs'])
|
||||
const events = workflow.on
|
||||
if (!isRecord(events)) throw new TypeError(`${file} must declare events`)
|
||||
expect(events).not.toHaveProperty('pull_request')
|
||||
expect(events).toHaveProperty('pull_request_target')
|
||||
for (const job of jobs) {
|
||||
const check = stepsOf(workflowJob(workflow, job)).find(step => typeof step.uses === 'string' && step.uses.startsWith('deepseek-harness/deepseek-harness-check@'))
|
||||
if (check === undefined || !isRecord(check.env)) throw new TypeError(`${file} ${job} must run the check action with env`)
|
||||
expect(String(check.env.CHECK_MODE)).toContain('vars.MERGE_POLICY_')
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps the pre-merge build behind the merge step, which honours the mode on its failures', () => {
|
||||
const steps = stepsOf(workflowJob(loadWorkflow('.github/workflows/pr-check-on-head-branch.yml'), 'pre-merge'))
|
||||
const merge = steps.findIndex(step => step.id === 'merge')
|
||||
const build = steps.findIndex(step => step.name === 'Run the pre-merge command')
|
||||
expect(merge).toBeGreaterThanOrEqual(0)
|
||||
expect(build).toBeGreaterThan(merge)
|
||||
const merging = steps[merge]
|
||||
if (merging === undefined || !isRecord(merging.env)) throw new TypeError('the merge step must set env')
|
||||
expect(String(merging.env.CHECK_MODE)).toContain('MERGE_POLICY_PRE_MERGE')
|
||||
for (const step of steps.slice(merge)) {
|
||||
if (typeof step.run !== 'string') continue
|
||||
expect(step.run).toContain('"$CHECK_MODE" = block')
|
||||
}
|
||||
for (const step of steps.slice(merge + 1)) {
|
||||
if (step.name === 'Run the pre-merge command') continue
|
||||
expect(step.if).toBe("steps.merge.outputs.merged == 'true'")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user