fix: 识别线上热修 Squash 等价提交
部署防覆盖校验支持补丁等价判断,避免平台仅允许 Squash 时误拦已合入主线的线上热修复。
This commit is contained in:
parent
2901bc6396
commit
dd7d2d2e28
@ -30,11 +30,31 @@ set -euo pipefail
|
||||
|
||||
release_includes_commit() {
|
||||
git merge-base --is-ancestor "$1" "$2" 2>/dev/null && return 0
|
||||
# Squash 改变提交身份;仅接受历史中完整文件树一致的提交。
|
||||
# Squash 改变提交身份;先接受历史中完整文件树一致的提交。
|
||||
local previous_tree release_trees
|
||||
previous_tree="$(git rev-parse "${1}^{tree}" 2>/dev/null)" || return 1
|
||||
release_trees="$(git log --format=%T "$2" 2>/dev/null)" || return 1
|
||||
printf '%s\n' "$release_trees" | grep -Fx -- "$previous_tree" >/dev/null
|
||||
if printf '%s\n' "$release_trees" | grep -Fx -- "$previous_tree" >/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 线上热修复可能基于旧主线,Squash 后补丁相同但父提交不同。只有线上独有
|
||||
# 的非合并提交都能在发布历史中找到等价补丁,且合并提交没有冲突解决内容时,
|
||||
# 才允许通过;任何真实新增或丢失的改动仍会被拦截。
|
||||
local unmerged_commits unique_merges merge conflict_resolution
|
||||
unmerged_commits="$(git cherry "$2" "$1" 2>/dev/null)" || return 1
|
||||
if printf '%s\n' "$unmerged_commits" | grep -q '^+ '; then
|
||||
return 1
|
||||
fi
|
||||
unique_merges="$(git rev-list --merges "$1" "^$2" 2>/dev/null)" || return 1
|
||||
while IFS= read -r merge; do
|
||||
[ -n "$merge" ] || continue
|
||||
conflict_resolution="$(git show --cc --format= "$merge" 2>/dev/null)" || return 1
|
||||
[ -z "$conflict_resolution" ] || return 1
|
||||
done <<EOF
|
||||
$unique_merges
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
server='218.93.190.75'
|
||||
|
||||
@ -62,13 +62,30 @@ function Test-CaiwuReleaseIncludesCommit {
|
||||
git merge-base --is-ancestor $PreviousSha $ReleaseSha 2>$null
|
||||
if ($LASTEXITCODE -eq 0) { return $true }
|
||||
|
||||
# Squash 会改变提交身份;只接受发布历史中完整文件树一致的提交。
|
||||
# 不按提交说明、部分文件或 patch 相似度放行。
|
||||
# Squash 会改变提交身份;先接受发布历史中完整文件树一致的提交。
|
||||
$previousTree = (git rev-parse "${PreviousSha}^{tree}" 2>$null) -join ''
|
||||
if ($LASTEXITCODE -ne 0) { return $false }
|
||||
$releaseTrees = @(git log --format=%T $ReleaseSha 2>$null)
|
||||
if ($LASTEXITCODE -ne 0) { return $false }
|
||||
return $releaseTrees -contains $previousTree
|
||||
if ($releaseTrees -contains $previousTree) { return $true }
|
||||
|
||||
# 线上热修复可能基于旧主线,Squash 后补丁相同但父提交不同。只有线上独有
|
||||
# 的非合并提交都能在发布历史中找到等价补丁,且合并提交没有冲突解决内容时,
|
||||
# 才允许通过;任何真实新增或丢失的改动仍会被拦截。
|
||||
$unmergedCommits = @(git cherry $ReleaseSha $PreviousSha 2>$null)
|
||||
if ($LASTEXITCODE -ne 0) { return $false }
|
||||
if ($unmergedCommits | Where-Object { $_ -match '^\+ ' }) { return $false }
|
||||
|
||||
$uniqueMerges = @(git rev-list --merges $PreviousSha "^$ReleaseSha" 2>$null)
|
||||
if ($LASTEXITCODE -ne 0) { return $false }
|
||||
foreach ($merge in $uniqueMerges) {
|
||||
$conflictResolution = @(git show --cc --format= $merge 2>$null)
|
||||
if ($LASTEXITCODE -ne 0 -or ($conflictResolution -join "`n").Trim() -ne '') {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
function Invoke-Native {
|
||||
|
||||
@ -39,6 +39,11 @@ try {
|
||||
Invoke-FixtureGit switch main | Out-Null
|
||||
$squashed=New-FixtureCommit 'hotfix content' 'squashed identity'
|
||||
$release=New-FixtureCommit 'next authorized change' 'new release'
|
||||
Invoke-FixtureGit switch -c equivalent-patch $base | Out-Null
|
||||
[IO.File]::WriteAllText((Join-Path $fixture 'context.txt'),'different parent tree')
|
||||
Invoke-FixtureGit add context.txt | Out-Null
|
||||
Invoke-FixtureGit commit -m 'different parent context' | Out-Null
|
||||
$equivalentPatch=New-FixtureCommit 'hotfix content' 'equivalent squash on newer base'
|
||||
Invoke-FixtureGit switch -c unrelated $base | Out-Null
|
||||
$unrelated=New-FixtureCommit 'different hotfix content' 'hotfix'
|
||||
$cases=@(
|
||||
@ -46,6 +51,7 @@ try {
|
||||
@{name='same commit';previous=$hotfix;release=$hotfix;expected=$true},
|
||||
@{name='identical squash tree at head';previous=$hotfix;release=$squashed;expected=$true},
|
||||
@{name='identical squash tree in release ancestry';previous=$hotfix;release=$release;expected=$true},
|
||||
@{name='equivalent patch on different parent tree';previous=$hotfix;release=$equivalentPatch;expected=$true},
|
||||
@{name='real unmerged change';previous=$unrelated;release=$release;expected=$false},
|
||||
@{name='rollback to before hotfix';previous=$hotfix;release=$base;expected=$false},
|
||||
@{name='missing deployed commit';previous=('0'*40);release=$release;expected=$false},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user