给你的Hexo博客添加自动化更新日志

三葉Leaves Author

用于发布文章:

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()

# 匹配两个 --- 之间的 frontmatter frontmatter_match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not frontmatter_match:
return None

frontmatter = frontmatter_match.group(1)
# 使用 yaml 解析 frontmatter metadata = yaml.safe_load(frontmatter)
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)

# 设置 Git 环境变量
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)

用于发布功能更新:

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
from git import Repo  
from datetime import datetime
import os
import re
import subprocess
import sys


def format_commit_message(message):
"""
格式化commit消息
如果消息格式为"ArticlePublish[yyyy-mm-dd HH:MM:SS]",
则转换为"于[yyyy-mm-dd HH:MM:SS]更新了文章"
""" pattern = r"ArticlePublish\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]"
match = re.match(pattern, message.strip())
if match:
timestamp = match.group(1)
return f"于[{timestamp}]更新了文章"
return message.strip()


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)


def get_commit_history(repo_path, output_file):
"""
读取git仓库的commit历史并输出为markdown格式

Parameters: repo_path (str): git仓库的本地路径
output_file (str): 输出markdown文件的路径
""" try:
# 打开git仓库
repo = Repo(repo_path)

# 获取所有commit
commits = list(repo.iter_commits('main'))

with open(output_file, 'w', encoding='utf-8') as f:
# 写入自定义头部
write_header(f)

# 遍历每个commit
for commit in commits:
# 格式化commit时间
commit_time = datetime.fromtimestamp(commit.committed_date).strftime('%Y-%m-%d %H:%M:%S')

# 获取修改的文件列表
files_changed = []
try:
for parent in commit.parents:
diff = parent.diff(commit)
files_changed.extend([d.a_path for d in diff])
except:
pass

# 处理commit信息
formatted_message = format_commit_message(commit.message)

# 构建GitHub commit链接
github_url = f"https://github.com/LeavesWebber/LeavesBlog/commit/{commit.hexsha}"

# 写入commit信息
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 %}#### ' + formatted_message + '{% endnote %} \n')
f.write(f' \n')
f.write(f'---\n')

print(f'Commit history has been exported to {output_file}')

except Exception as e:
print(f'Error: {str(e)}')


def execute_commands(repo_path, commit_message):
"""
执行Hexo和Git命令
""" # 设置 Git 环境变量,确保正确处理中文
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.encode("utf-8").decode("utf-8")}"', # 确保正确编码
'git push'
]

try:
# 切换到仓库目录
os.chdir(repo_path)

# 依次执行命令
for cmd in commands:
print(f'执行命令: {cmd}')
# 使用 Popen 替代 run,以更好地控制输入输出
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)}')


# 使用示例
if __name__ == '__main__':
# 检查命令行参数
if len(sys.argv) != 2:
print('使用方法: python publish.py "commit消息"')
sys.exit(1)

# 获取commit消息并确保正确编码
try:
commit_message = sys.argv[1].encode('utf-8').decode('utf-8')
except UnicodeError:
# 如果编码失败,尝试其他编码方式
try:
commit_message = sys.argv[1].encode('gbk').decode('utf-8')
except UnicodeError:
commit_message = sys.argv[1]

# 设置路径
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, commit_message)
  • 标题: 给你的Hexo博客添加自动化更新日志
  • 作者: 三葉Leaves
  • 创建于 : 2024-11-12 00:00:00
  • 更新于 : 2024-11-23 16:44:12
  • 链接: https://leavesblog.netlify.app/ed820b767b4e/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
给你的Hexo博客添加自动化更新日志