|
|
@@ -27,6 +27,25 @@ const legalIssue = {
|
|
|
stateReason: null,
|
|
|
}
|
|
|
|
|
|
+const canonicalKinds = [
|
|
|
+ 'kind/feature',
|
|
|
+ 'kind/bug-fix',
|
|
|
+ 'kind/doc',
|
|
|
+ 'kind/testing',
|
|
|
+ 'kind/cleanup',
|
|
|
+ 'kind/dependency',
|
|
|
+]
|
|
|
+
|
|
|
+const reviewedPull = (labels) => ({
|
|
|
+ isDraft: false,
|
|
|
+ authorType: 'User',
|
|
|
+ reviewRequestCount: 1,
|
|
|
+ reviewCount: 0,
|
|
|
+ labels,
|
|
|
+ references: { all: [2], resolving: [], related: [2] },
|
|
|
+ issues: new Map([[2, { priority: null }]]),
|
|
|
+})
|
|
|
+
|
|
|
test('counts only text outside details', () => {
|
|
|
assert.deepEqual(countVisibleUnits('支持 GitHub Project。<details>隐藏文字</details>'), {
|
|
|
units: 4,
|
|
|
@@ -92,6 +111,32 @@ test('rejects metadata prefixes in an Issue title', () => {
|
|
|
assert.ok(errors.includes('Issue 标题不得带 Type、Priority、Status、area 或 Owner 前缀'))
|
|
|
})
|
|
|
|
|
|
+test('reserves PR kind and legacy labels for pull requests', () => {
|
|
|
+ for (const label of [
|
|
|
+ ...canonicalKinds,
|
|
|
+ 'kind/experimental',
|
|
|
+ 'kind/bug',
|
|
|
+ 'kind/documentation',
|
|
|
+ 'bug-fix',
|
|
|
+ 'doc',
|
|
|
+ 'cleanup',
|
|
|
+ 'testing',
|
|
|
+ 'dependencies',
|
|
|
+ 'ci',
|
|
|
+ 'cli',
|
|
|
+ 'llm',
|
|
|
+ 'web-search',
|
|
|
+ ]) {
|
|
|
+ assert.ok(
|
|
|
+ validateIssue({ ...legalIssue, labels: [label] }).some((error) =>
|
|
|
+ error.startsWith('Issue 不得使用 PR kind 或旧版标签:'),
|
|
|
+ ),
|
|
|
+ label,
|
|
|
+ )
|
|
|
+ }
|
|
|
+ assert.deepEqual(validateIssue({ ...legalIssue, labels: ['area/web', 'source/member'] }), [])
|
|
|
+})
|
|
|
+
|
|
|
test('keeps terminal Status aligned with the native close reason', () => {
|
|
|
assert.deepEqual(
|
|
|
validateIssue({ ...legalIssue, status: 'Done', state: 'closed', stateReason: 'completed' }),
|
|
|
@@ -260,22 +305,51 @@ test('requires repository PR labels in the enforcement scope', () => {
|
|
|
references: { all: [2], resolving: [], related: [2] },
|
|
|
issues: new Map([[2, { priority: null }]]),
|
|
|
})
|
|
|
- assert.ok(errors.includes('PR 必须恰好有一个 kind/*,当前为 0'))
|
|
|
+ assert.ok(errors.includes('PR 必须恰好有一个允许的 kind/*,当前为 0'))
|
|
|
assert.ok(errors.includes('PR 必须至少有一个 area/*'))
|
|
|
})
|
|
|
|
|
|
-test('accepts repository-extensible kind labels', () => {
|
|
|
- assert.deepEqual(
|
|
|
- validatePullRequest({
|
|
|
- isDraft: false,
|
|
|
- authorType: 'User',
|
|
|
- reviewRequestCount: 1,
|
|
|
- reviewCount: 0,
|
|
|
- labels: ['kind/dependency', 'area/infra'],
|
|
|
- references: { all: [2], resolving: [], related: [2] },
|
|
|
- issues: new Map([[2, { priority: null }]]),
|
|
|
- }),
|
|
|
- [],
|
|
|
+test('accepts exactly the canonical kinds with extensible areas', () => {
|
|
|
+ for (const kind of canonicalKinds) {
|
|
|
+ assert.deepEqual(validatePullRequest(reviewedPull([kind, 'area/future-domain'])), [], kind)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+test('rejects multiple, unknown, legacy, and Issue-source PR labels', () => {
|
|
|
+ assert.ok(
|
|
|
+ validatePullRequest(
|
|
|
+ reviewedPull(['kind/feature', 'kind/doc', 'area/web']),
|
|
|
+ ).includes('PR 必须恰好有一个允许的 kind/*,当前为 2'),
|
|
|
+ )
|
|
|
+ assert.ok(
|
|
|
+ validatePullRequest(reviewedPull(['kind/experimental', 'area/web'])).includes(
|
|
|
+ 'PR 含不支持的 kind/*:kind/experimental',
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ for (const label of [
|
|
|
+ 'kind/bug',
|
|
|
+ 'kind/documentation',
|
|
|
+ 'bug-fix',
|
|
|
+ 'doc',
|
|
|
+ 'cleanup',
|
|
|
+ 'testing',
|
|
|
+ 'dependencies',
|
|
|
+ 'ci',
|
|
|
+ 'cli',
|
|
|
+ 'llm',
|
|
|
+ 'web-search',
|
|
|
+ ]) {
|
|
|
+ assert.ok(
|
|
|
+ validatePullRequest(reviewedPull(['kind/feature', 'area/web', label])).some((error) =>
|
|
|
+ error.startsWith('PR 含旧版标签:'),
|
|
|
+ ),
|
|
|
+ label,
|
|
|
+ )
|
|
|
+ }
|
|
|
+ assert.ok(
|
|
|
+ validatePullRequest(
|
|
|
+ reviewedPull(['kind/feature', 'area/web', 'source/internal-pr']),
|
|
|
+ ).includes('source/* 仅用于 Issue:source/internal-pr'),
|
|
|
)
|
|
|
})
|
|
|
|