Files
dingtalk-workspace-cli/test/scripts/coverage_baseline_repair_identity_test.go
chichuan b45eba0f5c fix(ci): tolerate merged PR base advancement
Bind coverage repair to the stable PR head and merge identity plus protected-main containment without treating the live base SHA projection as permanent identity.

Add semantic regression coverage for base advancement and update the governance documentation.
2026-08-25 14:06:09 +08:00

146 lines
4.4 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
package scripts_test
import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"gopkg.in/yaml.v3"
)
const stableMergedPRIdentityHelper = `function isStableMergedPRIdentity(
currentPull,
pullNumber,
headSha,
mergeCommitSha,
) {
return (
currentPull?.number === pullNumber &&
currentPull.state === 'closed' &&
currentPull.merged === true &&
typeof currentPull.merged_at === 'string' &&
currentPull.merged_at.length > 0 &&
currentPull.base?.ref === 'main' &&
currentPull.head?.sha === headSha &&
currentPull.merge_commit_sha === mergeCommitSha
);
}`
func TestCoverageBaselineRepairUsesStableMergedPRIdentity(t *testing.T) {
t.Parallel()
node, err := exec.LookPath("node")
if err != nil {
t.Skip("node is required to verify merged-PR repair identity semantics")
}
root, err := filepath.Abs(filepath.Join("..", ".."))
if err != nil {
t.Fatalf("resolve repository root: %v", err)
}
workflowPath := filepath.Join(
root,
".github",
"workflows",
"coverage-baseline-repair.yml",
)
data, err := os.ReadFile(workflowPath)
if err != nil {
t.Fatalf("read %s: %v", workflowPath, err)
}
workflow := string(data)
var parsedWorkflow any
if err := yaml.Unmarshal(data, &parsedWorkflow); err != nil {
t.Fatalf("parse %s: %v", workflowPath, err)
}
var scripts []string
collectGitHubScripts(parsedWorkflow, &scripts)
helperCount := 0
checkCount := 0
for _, script := range scripts {
helperCount += strings.Count(script, stableMergedPRIdentityHelper)
checkCount += strings.Count(script, "!isStableMergedPRIdentity(")
}
if helperCount != 2 {
t.Fatalf("stable merged-PR identity helper occurrences = %d, want dispatcher and producer", helperCount)
}
if checkCount != 2 {
t.Fatalf("stable merged-PR identity checks = %d, want dispatcher and producer", checkCount)
}
for _, forbidden := range []string{
"currentPull.base.sha",
"const baseSha =",
"base_sha",
} {
if strings.Contains(workflow, forbidden) {
t.Errorf("merged-PR repair must not bind mutable Ref SHA via %q", forbidden)
}
}
for _, want := range []string{
"const baseRef = eventPull?.base?.ref;",
"baseRef !== 'main'",
"const headSha = eventPull?.head?.sha;",
"const headSha = payload.head_sha;",
"head_sha: headSha",
"currentPull.head?.sha === headSha",
"currentPull.merge_commit_sha === mergeCommitSha",
"await requireMainContainment(mergeCommitSha)",
"await requireMainContainment(targetSha)",
} {
if !strings.Contains(workflow, want) {
t.Errorf("merged-PR repair missing stable identity guard %q", want)
}
}
verification := stableMergedPRIdentityHelper + `
const pullNumber = 1077;
const headSha = '1'.repeat(40);
const mergeCommitSha = '2'.repeat(40);
const validPull = {
number: pullNumber,
state: 'closed',
merged: true,
merged_at: '2026-08-25T04:55:30Z',
base: {ref: 'main', sha: '3'.repeat(40)},
head: {sha: headSha},
merge_commit_sha: mergeCommitSha,
};
const cases = [
['base ref advanced after event', {...validPull, base: {...validPull.base, sha: '4'.repeat(40)}}, true],
['base sha omitted by projection', {...validPull, base: {ref: 'main'}}, true],
['wrong pull number', {...validPull, number: pullNumber + 1}, false],
['open pull request', {...validPull, state: 'open'}, false],
['not merged', {...validPull, merged: false}, false],
['missing merged at', {...validPull, merged_at: null}, false],
['empty merged at', {...validPull, merged_at: ''}, false],
['non-string merged at', {...validPull, merged_at: 1}, false],
['wrong base ref', {...validPull, base: {...validPull.base, ref: 'release'}}, false],
['missing base ref', {...validPull, base: {}}, false],
['missing head', {...validPull, head: null}, false],
['wrong head sha', {...validPull, head: {sha: '5'.repeat(40)}}, false],
['wrong merge sha', {...validPull, merge_commit_sha: '6'.repeat(40)}, false],
['null pull', null, false],
];
for (const [name, currentPull, want] of cases) {
const got = isStableMergedPRIdentity(
currentPull,
pullNumber,
headSha,
mergeCommitSha,
);
if (got !== want) {
throw new Error(name + ': got ' + got + ', want ' + want);
}
}
`
command := exec.Command(node, "-e", verification)
if output, runErr := command.CombinedOutput(); runErr != nil {
t.Fatalf("stable merged-PR identity verification failed: %v\n%s", runErr, output)
}
}