1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
| from git import Repo from datetime import datetime import os import re import subprocess import yaml def extract_title_from_frontmatter(file_path): """ 从文章的 frontmatter 中提取 title """ try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() if not frontmatter_match: return None frontmatter = frontmatter_match.group(1) return metadata.get('title') except Exception: return None def get_changed_articles(repo_path): """ 获取最近一次提交中变更的文章信息 返回新增和修改的文章标题列表 """ repo = Repo(repo_path) posts_path = os.path.join(repo_path, 'source', '_posts') if not repo.head.is_valid(): return [], [] current_commit = repo.head.commit if not current_commit.parents: added_files = [] for root, _, files in os.walk(posts_path): for file in files: if file.endswith('.md'): file_path = os.path.join(root, file) rel_path = os.path.relpath(file_path, repo_path) added_files.append(rel_path) modified_files = [] else: parent_commit = current_commit.parents[0] diff = parent_commit.diff(current_commit) added_files = [] modified_files = [] for d in diff: if d.a_path and d.a_path.startswith('source/_posts/') and d.a_path.endswith('.md'): if d.change_type == 'A': added_files.append(d.a_path) elif d.change_type == 'M': modified_files.append(d.a_path) added_titles = [] modified_titles = [] for file in added_files: full_path = os.path.join(repo_path, file) title = extract_title_from_frontmatter(full_path) if title: added_titles.append(title) for file in modified_files: full_path = os.path.join(repo_path, file) title = extract_title_from_frontmatter(full_path) if title: modified_titles.append(title) return added_titles, modified_titles def build_commit_message(added_titles, modified_titles): """ 根据变更的文章构建提交信息 """ parts = [] if added_titles: parts.append(f"新增了文章:{', '.join(added_titles)}") if modified_titles: parts.append(f"更新了文章:{', '.join(modified_titles)}") if not parts: return "无文章变更" return "$" + ";".join(parts) def format_commit_message(message): """ 格式化commit消息为markdown格式 """ if not message.startswith('$'): return f'#### 提交信息:\n- {message.strip()}' message = message[1:] parts = message.split(';') formatted_parts = [] for part in parts: if '新增了文章:' in part: titles = part.replace('新增了文章:', '').split('、') formatted_parts.append('#### 新增了文章:\n' + '\n'.join(f'- {title.strip()}' for title in titles)) elif '更新了文章:' in part: titles = part.replace('更新了文章:', '').split('、') formatted_parts.append('#### 更新了文章:\n' + '\n'.join(f'- {title.strip()}' for title in titles)) return '\n'.join(formatted_parts) def get_commit_history(repo_path, output_file): """ 读取git仓库的commit历史并输出为markdown格式 """ try: repo = Repo(repo_path) commits = list(repo.iter_commits('main')) with open(output_file, 'w', encoding='utf-8') as f: write_header(f) for commit in commits: commit_time = datetime.fromtimestamp(commit.committed_date).strftime('%Y-%m-%d %H:%M:%S') formatted_message = format_commit_message(commit.message) if formatted_message == "无文章变更": continue github_url = f"https://github.com/LeavesWebber/LeavesBlog/commit/{commit.hexsha}" f.write(f'---\n') f.write(f'### 🔄 版本号: [{commit.hexsha[:8]}]({github_url})\n\n') f.write(f'**发布者:** 三葉Leaves <{commit.author.email}>\n\n') f.write(f'**更新日期:** {commit_time}\n\n') f.write('{% note blue fa-bolt %} \n') f.write(formatted_message) f.write('\n{% endnote %} \n') f.write(f' \n') f.write(f'---\n') except Exception as e: print(f'Error: {str(e)}') def execute_commands(repo_path): """ 执行Hexo和Git命令 """ added_titles, modified_titles = get_changed_articles(repo_path) commit_message = build_commit_message(added_titles, modified_titles) my_env = os.environ.copy() my_env["LANG"] = "zh_CN.UTF-8" commands = [ 'hexo clean', 'hexo g', 'hexo d', 'git add .', f'git commit -m "{commit_message}"', 'git push' ] try: os.chdir(repo_path) for cmd in commands: print(f'执行命令: {cmd}') process = subprocess.Popen( cmd, shell=True, env=my_env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8', errors='ignore' ) stdout, stderr = process.communicate() if process.returncode == 0: print(f'{cmd} 执行成功') if stdout: print(stdout) else: print(f'{cmd} 执行失败') if stderr: print(stderr) except Exception as e: print(f'发生错误: {str(e)}') def write_header(file): """ 写入文章头部内容 """ header = '''--- title: 叶子的Blog网站更新日志 date: 2024-11-10 04:00:00 updated: tags: - 日志 - 建站 - 运维 permalink: Gitlog excerpt: 💡该文档能帮助你知道 我的Blog网站 的任何更新情况,无论是新增功能、文章更新还是bug修复。内容由 Python 脚本根据我的 Git 记录自动生成💡 cover: https://ybkjzj.com:5555/d/webImage/%E8%88%AA%E5%A4%A9%20%E5%9C%B0%E7%90%83%20%E8%88%AA%E6%8B%8D%E7%85%A7%E7%89%87%204k%E9%A3%8E%E6%99%AF%E5%A3%81%E7%BA%B8_%E5%BD%BC%E5%B2%B8%E5%9B%BE%E7%BD%91.jpg comment: true categories: --- {% note primary fa-regular fa-robot %} 该文是我编写的`Python`脚本根据我的`Git`记录**动态生成**的。 {% endnote %} > 💡该文档能帮助你知道 我的Blog网站 的**任何更新**情况,无论是新增功能、文章更新还是bug修复。 > 💡你可以把它理解为我整个网站的**更新日志**。如此以来,我最近对我的网站做了什么,有没有发布新文章便都一目了然了。 \n\n\n---\n''' file.write(header)
if __name__ == '__main__': repo_path = r"D:\Projects\LeavesBlog" output_file = r"D:\Projects\LeavesBlog\source\_posts\Blog建站\叶子的Blog网站更新日志.md" get_commit_history(repo_path, output_file) execute_commands(repo_path)
|