历史分支中存在两条开发号 0.1.1;归档选择按 SHA 匹配,保留原编号与冲突标签。 增加同号前置说明遮蔽及错 SHA 不复用回归,标签计划使用相同精确选择方式。 已运行:定向 Go 测试、快照工具临时仓正反例及整仓 make verify;未部署。
This commit is contained in:
@@ -76,6 +76,12 @@
|
||||
> `0.1.12`),由 `scripts/version.py` 从 git **算出来**;开发交付的独立说明写入本文件“开发快照”章节,并打 `snapshot/vX.Y.Z` 注释标签 ⇒ 每次开发交付均可追溯,
|
||||
> 但"发布版本"仍然只能由人定(CI 不会自动升版本、不会打 tag)。
|
||||
|
||||
## 开发快照 snapshot/v0.1.27 - 2026-10-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- 并行分支存在同号开发提交时,历史变更说明与补记标签计划按完整 SHA 选择,不再被前一条同号记录遮蔽;不强改推导版本号或移动既有标签。
|
||||
|
||||
## 开发快照 snapshot/v0.1.26 - 2026-10-18
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -6,6 +6,12 @@ import (
|
||||
|
||||
// Development headings cannot replace the formal release baseline.
|
||||
func ExtractDevelopmentNotes(changelog, version string) string {
|
||||
return developmentNotes(changelog, version, "")
|
||||
}
|
||||
func ExtractDevelopmentNotesForCommit(changelog, version, sha string) string {
|
||||
return developmentNotes(changelog, version, sha)
|
||||
}
|
||||
func developmentNotes(changelog, version, sha string) string {
|
||||
if !SemverValid(version) {
|
||||
return ""
|
||||
}
|
||||
@@ -20,7 +26,15 @@ func ExtractDevelopmentNotes(changelog, version string) string {
|
||||
break
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(strings.Join(lines[i+1:end], "\n"))
|
||||
body := strings.TrimSpace(strings.Join(lines[i+1:end], "\n"))
|
||||
if sha == "" {
|
||||
return body
|
||||
}
|
||||
for _, field := range lines[i+1 : end] {
|
||||
if strings.TrimSpace(field) == "目标提交:"+sha {
|
||||
return body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
||||
@@ -55,6 +55,14 @@ func TestHistoricDevelopmentArchiveBindsExactCommit(t *testing.T) {
|
||||
t.Fatal("archived notes missing")
|
||||
}
|
||||
}
|
||||
// Parallel branch histories may legitimately have the same derived number.
|
||||
input.DeliveryArchive = strings.ReplaceAll(archive, shaB, strings.Repeat("c", 40)) + "\n" + archive
|
||||
result = DeriveVersions(input)
|
||||
for _, v := range result.Records {
|
||||
if v.CommitSHA == shaB && !strings.Contains(v.ReleaseNotes, "historic delivery notes") {
|
||||
t.Fatal("same-number archive hid notes for exact commit")
|
||||
}
|
||||
}
|
||||
input.DeliveryArchive = strings.ReplaceAll(archive, shaB, strings.Repeat("c", 40))
|
||||
result = DeriveVersions(input)
|
||||
for _, v := range result.Records {
|
||||
|
||||
@@ -198,10 +198,7 @@ func DeriveVersions(in DeriveInput) DeriveResult {
|
||||
} else if kind == governance.RecordKindDevelopment {
|
||||
record.ReleaseNotes = governance.ExtractDevelopmentNotes(changelog, label)
|
||||
if record.ReleaseNotes == "" {
|
||||
archived := governance.ExtractDevelopmentNotes(in.DeliveryArchive, label)
|
||||
if strings.Contains(archived, "目标提交:"+commit.SHA) {
|
||||
record.ReleaseNotes = archived
|
||||
}
|
||||
record.ReleaseNotes = governance.ExtractDevelopmentNotesForCommit(in.DeliveryArchive, label, commit.SHA)
|
||||
}
|
||||
if record.ReleaseNotes == "" {
|
||||
for _, tag := range tagsByTarget[commit.SHA] {
|
||||
|
||||
@@ -8,10 +8,11 @@ def git(root,*args):
|
||||
p=subprocess.run(['git',*args],cwd=root,text=True,capture_output=True)
|
||||
if p.returncode:raise RuntimeError('git operation failed: '+args[0])
|
||||
return p.stdout.strip()
|
||||
def notes(text,version):
|
||||
heading=re.search(r'^## 开发快照 snapshot/v'+re.escape(version)+r' - \d{4}-\d{2}-\d{2}\s*$',text,re.M)
|
||||
if not heading:return ''
|
||||
tail=text[heading.end():];return re.split(r'^##\s',tail,maxsplit=1,flags=re.M)[0].strip()
|
||||
def notes(text,version,sha=None):
|
||||
for heading in re.finditer(r'^## 开发快照 snapshot/v'+re.escape(version)+r' - \d{4}-\d{2}-\d{2}\s*$',text,re.M):
|
||||
body=re.split(r'^##\s',text[heading.end():],maxsplit=1,flags=re.M)[0].strip()
|
||||
if sha is None or ('目标提交:'+sha) in body.splitlines():return body
|
||||
return ''
|
||||
def plan(root,sha,backfill=False):
|
||||
if not sha or not SHA.fullmatch(sha):raise ValueError('exact 40-character commit SHA required')
|
||||
if git(root,'cat-file','-t',sha)!='commit':raise ValueError('snapshot target must be a commit')
|
||||
@@ -24,7 +25,7 @@ def plan(root,sha,backfill=False):
|
||||
if n<=0:raise ValueError('formal baseline cannot be tagged as a development delivery')
|
||||
body=notes(text,version)
|
||||
if not body and backfill:
|
||||
body=notes(git(root,'show','HEAD:CHANGELOG.md'),version)
|
||||
body=notes(git(root,'show','HEAD:CHANGELOG.md'),version,sha)
|
||||
if '目标提交:'+sha not in body:raise ValueError('backfilled notes must bind the exact historic SHA')
|
||||
if not body:raise ValueError('this development version has no independent CHANGELOG entry')
|
||||
if not re.search(r'^### (Added|Changed|Fixed|Security)\s*$',body,re.M):raise ValueError('snapshot notes have no change category')
|
||||
@@ -60,6 +61,8 @@ def self_test():
|
||||
(r/'CHANGELOG.md').write_text('## 开发快照 snapshot/v0.1.1 - 2026-10-18\n\n### Fixed\n\n- specific fixture fix\n\n'+base);git(r,'add','CHANGELOG.md');git(r,'commit','-m','fix: fixture change')
|
||||
sha=git(r,'rev-parse','HEAD');before=git(r,'tag');p=plan(r,sha)
|
||||
assert p['tag']=='snapshot/v0.1.1' and 'specific fixture fix' in p['message']
|
||||
duplicate='## 开发快照 snapshot/v0.1.1 - 2026-10-18\n\n目标提交:'+('a'*40)+'\n\n### Fixed\n\n- wrong branch\n\n## 开发快照 snapshot/v0.1.1 - 2026-10-18\n\n目标提交:'+sha+'\n\n### Fixed\n\n- exact branch'
|
||||
assert 'exact branch' in notes(duplicate,'0.1.1',sha) and 'wrong branch' not in notes(duplicate,'0.1.1',sha)
|
||||
assert before==git(r,'tag'),'planning wrote a tag'
|
||||
try:plan(r,'a'*7)
|
||||
except ValueError:pass
|
||||
|
||||
Reference in New Issue
Block a user