Skip to content

Commit f2dfb63

Browse files
author
吴红02
committed
fix(publish): default PR body to Closes #N when the brief has an issue - empty PR bodies left issues dangling after merge (auto-close needs the keyword); apply the same default to the release composite path; explicit --body still wins; regression test pins the POST body
1 parent 9d073c4 commit f2dfb63

3 files changed

Lines changed: 31 additions & 2 deletions

File tree

‎lib/domains/publish.mjs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import { pushAndOpenPr } from '../steps.mjs'
66

77
export async function planData(r, o) {
88
const n = name(o), b = brief(r, n), q = repo(r)
9-
return { name: n, repository: repository(b, r), branch: b.data.branch || q.branch, baseBranch: b.data.baseBranch || 'main', title: o.title || n, body: o.body || '', head: q.head, brief: b.data }
9+
// PR 正文缺省携带 Closes #N:brief 有关联 issue 时,PR 合入即自动关闭该 issue
10+
// (此前缺省空正文导致 issue 悬空);显式 --body 仍优先,plan/execute 同源保持哈希一致
11+
const issue = b.data.github && b.data.github.issue
12+
const body = o.body || (issue ? `Closes #${issue}\n\n完整 brief:shadow-docs/changes/${n}/brief.md` : '')
13+
return { name: n, repository: repository(b, r), branch: b.data.branch || q.branch, baseBranch: b.data.baseBranch || 'main', title: o.title || n, body, head: q.head, brief: b.data }
1014
}
1115

1216
export async function execute(r, o, x, b) {

‎lib/domains/release.mjs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ import { commitStep, pushAndOpenPr } from '../steps.mjs'
66

77
export async function planData(r, o) {
88
const n = name(o), b = brief(r, n), q = repo(r), w = b.data.workflow.release || {}
9+
// 与 publish 同源:PR 正文缺省携带 Closes #N(brief 有关联 issue 时合并即自动关闭)
10+
const issue = b.data.github && b.data.github.issue
11+
const body = o.body ?? w.body ?? (issue ? `Closes #${issue}\n\n完整 brief:shadow-docs/changes/${n}/brief.md` : '')
912
return {
1013
name: n,
1114
files: fileList(o.files ?? w.files),
1215
message: o.message ?? w.message ?? null,
1316
title: o.title ?? w.title ?? n,
14-
body: o.body ?? w.body ?? '',
17+
body,
1518
repository: repository(b, r),
1619
branch: b.data.branch || q.branch,
1720
baseBranch: b.data.baseBranch || 'main',

‎test/cli.test.mjs‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,28 @@ test('publish pushes normally and creates a PR when none exists', () => {
673673
} finally { api.close() }
674674
})
675675

676+
test('publish defaults the PR body to Closes #N when the brief has an issue', () => {
677+
const root = fixture()
678+
addOrigin(root)
679+
execFileSync('git', ['switch', '-c', 'feat/sample'], { cwd: root })
680+
writeFileSync(join(root, 'feature.txt'), 'feature\n')
681+
execFileSync('git', ['add', '--', 'feature.txt'], { cwd: root })
682+
execFileSync('git', ['commit', '-m', 'feature'], { cwd: root })
683+
updateBrief(root, data => { data.github.repository = 'owner/repo'; data.branch = 'feat/sample'; data.github.issue = 5 })
684+
const api = apiStub([
685+
{ method: 'GET', path: '/repos/owner/repo/pulls?', body: [] },
686+
{ method: 'POST', path: '/repos/owner/repo/pulls', body: { number: 9, html_url: 'https://github.test/pulls/9' } },
687+
])
688+
try {
689+
const args = ['--name', 'sample', '--title', 'Feature']
690+
const planned = run(['publish', 'plan', ...args, '--json'], root)
691+
const result = run(['publish', 'execute', ...args, '--plan-hash', JSON.parse(planned.stdout).planHash, '--confirm', '--json'], root, { GITHUB_TOKEN: 'token', SHADOW_GITHUB_API_URL: api.url })
692+
assert.equal(result.status, 0, result.stderr)
693+
const created = api.requests().find(request => request.method === 'POST')
694+
assert.match(JSON.parse(created.body).body, /Closes #5/)
695+
} finally { api.close() }
696+
})
697+
676698
test('publish reuses an existing open PR', () => {
677699
const root = fixture()
678700
addOrigin(root)

0 commit comments

Comments
 (0)