#!/usr/bin/env python3
"""
版本合规校验脚本 - 大厂标准版本管控
校验清单：
1. pom revision格式必须为X.Y.Z 或 X.Y.Z-SNAPSHOT
2. Git工作区无未提交变更（可选放开develop分支局部配置文件例外白名单）
3. release/vX.Y.Z分支必须无SNAPSHOT后缀
4. feature/hotfix分支必须继承develop的BASE大版本号，禁止跨大版本修改
5. 能正常读取8位commit哈希、分支名称

校验失败直接exit 1中断流水线
"""

import os
import re
import subprocess
import sys

def run_git_command(cmd):
    """执行git命令并返回结果"""
    try:
        result = subprocess.run(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            universal_newlines=True,
            cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        )
        return result.stdout.strip()
    except Exception as e:
        print(f"❌ Git命令执行失败: {e}")
        return None

def get_pom_version():
    """读取pom.xml中的revision版本号"""
    pom_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'pom.xml')
    if os.path.exists(pom_path):
        with open(pom_path, 'r', encoding='utf-8') as f:
            content = f.read()
            match = re.search(r'<revision>([^<]+)</revision>', content)
            if match:
                return match.group(1).strip()
    return None

def get_version_file_base():
    """读取VERSION文件中的基础版本号"""
    version_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'VERSION')
    if os.path.exists(version_path):
        with open(version_path, 'r', encoding='utf-8') as f:
            for line in f:
                if line.startswith('BASE_VERSION='):
                    return line.strip().split('=')[1].strip()
    return None

def is_dirty_workspace():
    """检查工作区是否有未提交的变更"""
    status = run_git_command(['git', 'status', '--porcelain'])
    if status:
        # 检查是否只有允许的临时文件变更
        lines = status.split('\n')
        allowed_patterns = [
            r'^.*\.log$',
            r'^.*\.tmp$',
            r'^.*target/.*$',
            r'^.*\.idea/.*$',
            r'^.*\.vscode/.*$',
            r'^frontend/.*$',           # 前端文件变更（版本同步脚本自动更新）
            r'^version\.json$',          # 版本信息文件（构建时自动生成）
            r'^VERSION$',                # VERSION文件（版本同步脚本自动更新）
        ]
        for line in lines:
            if line.strip():
                # git status --porcelain 格式可能是 "M path" (staged) 或 " M path" (not staged)
                # 使用split(None,1)按空格分割，取第二部分作为文件名
                parts = line.strip().split(None, 1)
                if len(parts) < 2:
                    continue
                filename = parts[1].strip()
                is_allowed = False
                for pattern in allowed_patterns:
                    if re.match(pattern, filename):
                        is_allowed = True
                        break
                if not is_allowed:
                    print(f"⚠️ 未提交的文件: {filename}")
                    return True
    return False

def validate_version_format(version):
    """校验版本号格式：X.Y.Z 或 X.Y.Z-SNAPSHOT"""
    pattern = r'^\d+\.\d+\.\d+(-SNAPSHOT)?$'
    return re.match(pattern, version) is not None

def validate_branch_version(branch, version):
    """校验分支与版本的绑定规则"""
    errors = []
    
    # release/vX.Y.Z分支必须无SNAPSHOT后缀
    if branch.startswith('release/v'):
        if '-SNAPSHOT' in version:
            errors.append(f"❌ release分支({branch})版本不能包含SNAPSHOT后缀，当前版本: {version}")
        
        # release分支版本号应与分支名匹配
        expected_base = branch.replace('release/v', '')
        actual_base = version.replace('-SNAPSHOT', '')
        if expected_base != actual_base:
            errors.append(f"❌ release分支版本不匹配: 分支名期望{expected_base}, 当前版本{actual_base}")
    
    # feature/hotfix分支必须有SNAPSHOT后缀
    if branch.startswith('feature/') or branch.startswith('hotfix/'):
        if '-SNAPSHOT' not in version:
            errors.append(f"❌ feature/hotfix分支({branch})版本必须包含SNAPSHOT后缀")
    
    # develop分支必须有SNAPSHOT后缀
    if branch == 'develop':
        if '-SNAPSHOT' not in version:
            errors.append(f"❌ develop分支版本必须包含SNAPSHOT后缀")
    
    # main分支不应该有SNAPSHOT后缀
    if branch == 'main':
        if '-SNAPSHOT' in version:
            errors.append(f"❌ main分支版本不能包含SNAPSHOT后缀")
    
    return errors

def validate_base_version_match(pom_version, version_file_base):
    """校验pom版本与VERSION文件BASE版本是否一致"""
    if version_file_base:
        pom_base = pom_version.replace('-SNAPSHOT', '')
        if pom_base != version_file_base:
            return f"❌ pom版本({pom_base})与VERSION文件({version_file_base})不一致"
    return None

def main():
    print("🔍 版本合规校验开始...")
    print("="*70)
    
    errors = []
    
    # 1. 获取基本信息
    pom_version = get_pom_version()
    version_file_base = get_version_file_base()
    branch = run_git_command(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
    commit_hash = run_git_command(['git', 'rev-parse', '--short=8', 'HEAD'])
    
    print(f"📋 当前分支: {branch}")
    print(f"📦 pom版本: {pom_version}")
    print(f"📁 VERSION文件: {version_file_base}")
    print(f"🔗 Commit: {commit_hash}")
    print()
    
    # 2. 校验版本格式
    if not pom_version:
        errors.append("❌ 无法读取pom.xml中的revision版本号")
    elif not validate_version_format(pom_version):
        errors.append(f"❌ 版本号格式错误: {pom_version} (要求: X.Y.Z 或 X.Y.Z-SNAPSHOT)")
    
    # 3. 校验分支与版本绑定
    if pom_version and branch:
        branch_errors = validate_branch_version(branch, pom_version)
        errors.extend(branch_errors)
    
    # 4. 校验VERSION文件与pom版本一致
    if pom_version and version_file_base:
        mismatch_error = validate_base_version_match(pom_version, version_file_base)
        if mismatch_error:
            errors.append(mismatch_error)
    
    # 5. 校验工作区干净（develop分支除外）
    if branch != 'develop' and is_dirty_workspace():
        errors.append("❌ Git工作区存在未提交的变更")
    
    # 6. 校验commit hash正常读取
    if not commit_hash or len(commit_hash) != 8:
        errors.append(f"❌ Commit哈希读取异常: {commit_hash} (期望8位)")
    
    # 输出结果
    print("="*70)
    if errors:
        print("❌ 版本合规校验失败:")
        for error in errors:
            print(f"   {error}")
        print("\n🚨 流水线中断，请修复以上问题后重新构建")
        sys.exit(1)
    else:
        print("✅ 版本合规校验通过!")
        print(f"\n📊 完整版本标识: {pom_version.replace('-SNAPSHOT', '')}-{branch.replace('/', '-')}-{commit_hash}")
        sys.exit(0)

if __name__ == '__main__':
    main()