#!/usr/bin/env python3 # git_auto_commit_with_skills_organize.py - 先整理 skills 文件夹,再自动提交到 Gitea # 用法: python git_auto_commit_with_skills_organize.py [目录路径] import os import sys import shutil import subprocess import tempfile from datetime import datetime from pathlib import Path from urllib.parse import urlparse # 配置 REPO_URL = "https://gittea.dev/popiskill/skills.git" BRANCH = "master" DEFAULT_SOURCE_DIR = "C:/ai/openclaw" # Windows 路径格式 SKILLS_BASE_DIR = "C:/ai/skills" # skills 文件夹根目录 # 分类映射 CATEGORY_MAPPING = { "内容创作": "content_creation", "图像制作": "image_generation", "视频制作": "video_production", "音频创作": "audio_creation", "AI剪辑": "AI_video_trim", "社媒运营": "social_media", "电商工具": "E-commerce_tools", "漫剧制作": "comic_drama" } # 排除的文件/目录 EXCLUDE_PATTERNS = ['.git', '.openclaw'] def load_config(): """从配置文件读取凭证""" script_dir = Path(__file__).parent config_file = script_dir / "git-config.env" if not config_file.exists(): print(f"错误: 配置文件不存在: {config_file}") print("请创建配置文件 git-config.env 并设置 GIT_USERNAME 和 GIT_PASSWORD") sys.exit(1) config = {} with open(config_file, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if line and not line.startswith('#') and '=' in line: key, value = line.split('=', 1) config[key.strip()] = value.strip().strip('"\'') if not config.get('GIT_USERNAME') or not config.get('GIT_PASSWORD'): print("错误: 请在配置文件中设置 GIT_USERNAME 和 GIT_PASSWORD") sys.exit(1) return config['GIT_USERNAME'], config['GIT_PASSWORD'] def build_auth_url(repo_url, username, token): """构建带凭证的 URL""" parsed = urlparse(repo_url) return f"{parsed.scheme}://{username}:{token}@{parsed.netloc}{parsed.path}" def copy_directory(src, dst, exclude=None): """复制目录,排除指定文件""" if exclude is None: exclude = [] src_path = Path(src) dst_path = Path(dst) for item in src_path.rglob('*'): # 检查是否在排除列表中 rel_path = item.relative_to(src_path) if any(part in exclude for part in rel_path.parts): continue if item.is_file(): target = dst_path / rel_path target.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(item, target) def run_git_command(args, cwd=None, check=True): """运行 git 命令""" result = subprocess.run( ['git'] + args, cwd=cwd, capture_output=True, text=True, encoding='utf-8' ) if check and result.returncode != 0: print(f"Git 错误: {result.stderr}") raise subprocess.CalledProcessError(result.returncode, ['git'] + args) return result def organize_skills(): """ 整理 C:/ai/skills 中的各个分类文件夹 为每个.zip文件创建同名文件夹,将.zip放入对应创建文件夹,并配一个install.md """ print("=" * 60) print("步骤 1: 整理 Skills 文件夹") print("=" * 60) base_path = Path(SKILLS_BASE_DIR) if not base_path.exists(): print(f"警告: Skills 目录不存在: {SKILLS_BASE_DIR}") return 0 total_processed = 0 for cat_name, cat_mapping in CATEGORY_MAPPING.items(): cat_path = base_path / cat_name if not cat_path.exists(): print(f"分类不存在,跳过: {cat_name}") continue print(f"\n处理分类: {cat_name} -> {cat_mapping}") # 只查找当前目录下的 .zip 文件(不递归) zip_files = list(cat_path.glob("*.zip")) for zip_file in zip_files: zip_name = zip_file.stem # 不含 .zip 扩展名 folder_path = cat_path / zip_name # 创建同名文件夹 if not folder_path.exists(): folder_path.mkdir(parents=True, exist_ok=True) print(f" [创建] {zip_name}/") # 移动 ZIP 文件到文件夹 dest_zip_path = folder_path / zip_file.name if not dest_zip_path.exists(): shutil.move(str(zip_file), str(dest_zip_path)) print(f" [移动] {zip_file.name}") # 创建 install.md install_md_path = folder_path / "install.md" zip_file_name = f"{zip_name}.zip" install_content = f"skill名称={zip_name} 请执行以下流程:下载 https://gittea.dev/popiskill/skills/raw/branch/master/{cat_mapping}/{zip_name}/{zip_file_name} 文件,将该zip 解压至openclaw根目录(skill安装) ./skills/{zip_name} 目录,然后删除下载的临时文件和文档。" with open(install_md_path, 'w', encoding='utf-8') as f: f.write(install_content) print(f" [创建] install.md") total_processed += 1 print(f"\n[完成] Skills 整理完成,共处理 {total_processed} 个 ZIP 文件") return total_processed def git_auto_commit(source_dir): """执行 Git 自动提交""" print("\n" + "=" * 60) print("步骤 2: Git 自动提交") print("=" * 60) source_path = Path(source_dir) if not source_path.exists(): print(f"错误: 目录不存在: {source_dir}") sys.exit(1) # 加载配置 username, token = load_config() # 创建临时工作目录 work_dir = tempfile.mkdtemp(prefix='git_auto_commit_') print(f"工作目录: {work_dir}") print(f"源目录: {source_dir}") try: # 构建带凭证的 URL auth_url = build_auth_url(REPO_URL, username, token) # 尝试克隆现有仓库 try: run_git_command(['clone', auth_url, '.'], cwd=work_dir) print("已克隆现有仓库") except subprocess.CalledProcessError: print("初始化新仓库...") run_git_command(['init'], cwd=work_dir) run_git_command(['remote', 'add', 'origin', auth_url], cwd=work_dir) # 复制文件到仓库 print("复制文件...") copy_directory(source_dir, work_dir, exclude=EXCLUDE_PATTERNS) # 配置 git run_git_command(['config', 'user.email', 'auto@commit.local'], cwd=work_dir) run_git_command(['config', 'user.name', 'Auto Commit'], cwd=work_dir) # 添加所有更改 run_git_command(['add', '-A'], cwd=work_dir) # 检查是否有更改要提交 status_result = run_git_command(['diff', '--cached', '--quiet'], cwd=work_dir, check=False) if status_result.returncode == 0: print("没有更改需要提交") return False # 提交并推送 commit_msg = f"Auto commit: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" run_git_command(['commit', '-m', commit_msg], cwd=work_dir) run_git_command(['push', 'origin', BRANCH], cwd=work_dir) print(f"[成功] 已提交到 {REPO_URL}") return True finally: # 清理临时目录 shutil.rmtree(work_dir, ignore_errors=True) def main(): # 获取源目录 if len(sys.argv) < 2: source_dir = DEFAULT_SOURCE_DIR print(f"未指定目录,使用默认: {source_dir}") else: source_dir = sys.argv[1] print("=" * 60) print("Git Auto Commit with Skills Organize") print(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print("=" * 60) # 步骤 1: 整理 skills 文件夹 skills_count = organize_skills() # 步骤 2: Git 自动提交 committed = git_auto_commit(source_dir) print("\n" + "=" * 60) print("执行完成") print(f"Skills 整理: {skills_count} 个") print(f"Git 提交: {'成功' if committed else '无更改或失败'}") print(f"结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print("=" * 60) if __name__ == '__main__': main()