【整合】 框架使用规则
This commit is contained in:
@@ -1,111 +1,106 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
提交前共享检查:推断变更文件所属模块,校验提交信息格式。
|
||||
|
||||
.DESCRIPTION
|
||||
读取 git diff 中变更的文件,根据 hooks/commit-module-mappings.json
|
||||
推断模块,然后校验提交信息是否符合 [模块][类型]: 描述 格式。
|
||||
|
||||
.PARAMETER Message
|
||||
待校验的提交信息。
|
||||
|
||||
.EXAMPLE
|
||||
.\docs\hooks\commit-check.ps1 -Message "[entity][docs]: 补充实体池说明"
|
||||
#>
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Message
|
||||
[string]$Message,
|
||||
[string]$RepositoryRoot = ''
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($RepositoryRoot)) {
|
||||
$RepositoryRoot = (Get-Location).Path
|
||||
}
|
||||
$RepositoryRoot = [System.IO.Path]::GetFullPath($RepositoryRoot)
|
||||
$gitRoot = & git -C $RepositoryRoot rev-parse --show-toplevel 2>$null | Select-Object -First 1
|
||||
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($gitRoot)) {
|
||||
Write-Error "Git repository was not found: $RepositoryRoot"
|
||||
exit 1
|
||||
}
|
||||
$RepositoryRoot = [System.IO.Path]::GetFullPath($gitRoot)
|
||||
|
||||
$mappingFile = Join-Path $PSScriptRoot 'commit-module-mappings.json'
|
||||
if (-not (Test-Path $mappingFile)) {
|
||||
Write-Error "Module mapping file not found: $mappingFile"
|
||||
$mapping = Get-Content -LiteralPath $mappingFile -Raw -Encoding UTF8 | ConvertFrom-Json
|
||||
|
||||
function Get-CommitFiles {
|
||||
param([string]$Root)
|
||||
|
||||
$staged = @(& git -C $Root -c core.quotepath=false diff --cached --name-only --diff-filter=ACMRD)
|
||||
$staged = @($staged | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
||||
if ($staged.Count -gt 0) {
|
||||
return $staged
|
||||
}
|
||||
|
||||
$files = @()
|
||||
$statusLines = & git -C $Root -c core.quotepath=false status --porcelain=v1 --untracked-files=all
|
||||
foreach ($line in $statusLines) {
|
||||
if ([string]::IsNullOrWhiteSpace($line) -or $line.Length -lt 4) {
|
||||
continue
|
||||
}
|
||||
$path = $line.Substring(3).Trim()
|
||||
if ($path.Contains(' -> ')) {
|
||||
$path = ($path -split ' -> ')[-1]
|
||||
}
|
||||
$files += $path.Replace('\', '/')
|
||||
}
|
||||
return @($files | Select-Object -Unique)
|
||||
}
|
||||
|
||||
function Get-Modules {
|
||||
param([string[]]$Files)
|
||||
|
||||
$modules = @()
|
||||
foreach ($file in $Files) {
|
||||
foreach ($entry in $mapping.mappings) {
|
||||
if ($file -match $entry.pattern) {
|
||||
$modules += $entry.module
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return @($modules | Select-Object -Unique)
|
||||
}
|
||||
|
||||
if ($Message -notmatch '^\[([^\]]+)\]\[([^\]]+)\]:\s+(.+)$') {
|
||||
Write-Error 'Commit message format must be: [module][type]: description'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$mapping = Get-Content $mappingFile -Raw | ConvertFrom-Json
|
||||
|
||||
function Get-ChangedFiles {
|
||||
$staged = (cmd /c "git diff --cached --name-only 2>nul") -split "`r?`n" | Where-Object { $_ }
|
||||
if (-not $staged) { $staged = @() }
|
||||
|
||||
$unstaged = (cmd /c "git diff --name-only 2>nul") -split "`r?`n" | Where-Object { $_ }
|
||||
if (-not $unstaged) { $unstaged = @() }
|
||||
|
||||
$all = @($staged) + @($unstaged) | Select-Object -Unique | Where-Object { $_ }
|
||||
return $all
|
||||
$messageModule = $Matches[1]
|
||||
$messageType = $Matches[2]
|
||||
$description = $Matches[3]
|
||||
if ([string]::IsNullOrWhiteSpace($description)) {
|
||||
Write-Error 'Commit message description is empty.'
|
||||
exit 1
|
||||
}
|
||||
if ($mapping.validTypes -notcontains $messageType) {
|
||||
Write-Error ("Invalid commit type '{0}'. Allowed types: {1}" -f
|
||||
$messageType, ($mapping.validTypes -join ', '))
|
||||
exit 1
|
||||
}
|
||||
|
||||
function Get-ModuleForFile($file) {
|
||||
foreach ($entry in $mapping.mappings) {
|
||||
if ($file -match $entry.pattern) {
|
||||
return $entry.module
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
$files = @(Get-CommitFiles $RepositoryRoot)
|
||||
$modules = @(Get-Modules $files)
|
||||
|
||||
function Get-ModulesFromChangedFiles($files) {
|
||||
$modules = @()
|
||||
foreach ($file in $files) {
|
||||
$module = Get-ModuleForFile $file
|
||||
if ($module) {
|
||||
$modules += $module
|
||||
}
|
||||
}
|
||||
return $modules | Select-Object -Unique
|
||||
}
|
||||
|
||||
function Test-CommitMessage($message, $modules) {
|
||||
if ($message -notmatch '^\[([^\]]+)\]\[([^\]]+)\]:\s*(.+)$') {
|
||||
return @{ IsValid = $false; Reason = '提交信息格式应为:[模块][类型]: 描述' }
|
||||
}
|
||||
|
||||
$msgModule = $Matches[1]
|
||||
$msgType = $Matches[2]
|
||||
$msgDesc = $Matches[3]
|
||||
|
||||
if (-not $msgDesc) {
|
||||
return @{ IsValid = $false; Reason = '提交信息缺少描述内容' }
|
||||
}
|
||||
|
||||
if ($mapping.validTypes -notcontains $msgType) {
|
||||
return @{ IsValid = $false; Reason = "无效的类型 '$msgType'。有效类型:$($mapping.validTypes -join ', ')" }
|
||||
}
|
||||
|
||||
if ($modules -and $modules -notcontains $msgModule) {
|
||||
Write-Warning "提交信息中的模块 [$msgModule] 与变更文件推断的模块 [$($modules -join ', ')] 不一致,请确认是否 intentional。"
|
||||
}
|
||||
|
||||
return @{ IsValid = $true; Reason = '' }
|
||||
}
|
||||
|
||||
$files = Get-ChangedFiles
|
||||
if (-not $files) {
|
||||
Write-Host "未检测到变更文件。" -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
|
||||
$modules = Get-ModulesFromChangedFiles $files
|
||||
|
||||
Write-Host "变更文件:"
|
||||
$files | ForEach-Object { Write-Host " - $_" }
|
||||
|
||||
if ($modules) {
|
||||
Write-Host "推断模块:$($modules -join ', ')"
|
||||
Write-Output ("Repository: {0}" -f $RepositoryRoot)
|
||||
if ($files.Count -eq 0) {
|
||||
Write-Warning 'No staged, unstaged, or untracked files were found. Only the message was validated.'
|
||||
}
|
||||
else {
|
||||
Write-Warning "未能从变更文件推断出模块,请检查提交信息是否手动指定了正确模块。"
|
||||
Write-Output 'Commit scope files:'
|
||||
foreach ($file in $files) {
|
||||
Write-Output (" - {0}" -f $file)
|
||||
}
|
||||
}
|
||||
|
||||
$result = Test-CommitMessage $Message $modules
|
||||
if (-not $result.IsValid) {
|
||||
Write-Error $result.Reason
|
||||
exit 1
|
||||
if ($modules.Count -gt 0) {
|
||||
Write-Output ("Detected modules: {0}" -f ($modules -join ', '))
|
||||
if ($modules -notcontains $messageModule) {
|
||||
Write-Warning ("Message module [{0}] does not match detected modules [{1}]. Review the commit scope." -f
|
||||
$messageModule, ($modules -join ', '))
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Warning 'No path mapping matched. Review the commit module manually.'
|
||||
}
|
||||
|
||||
Write-Host "提交信息格式正确。" -ForegroundColor Green
|
||||
Write-Output 'Commit message is valid.'
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user