-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathbuild_weekly_release.py
More file actions
243 lines (213 loc) · 9 KB
/
Copy pathbuild_weekly_release.py
File metadata and controls
243 lines (213 loc) · 9 KB
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
233
234
235
236
237
238
239
240
241
242
243
# generate_release.py
import os
import re
import json
import requests
from pathlib import Path
from datetime import datetime, timedelta, timezone
from typing import Optional
from urllib.parse import unquote
from process_changes import slugify, get_summary_file_path
# 常量定义
BOOKMARK_SUMMARY_REPO_NAME = '.' # 当前目录
# 定义UTC+8时区
UTC_PLUS_8 = timezone(timedelta(hours=8))
# 干运行模式,设为True时不会实际创建发布
DRY_RUN = False
def extract_tldr(summary_file: Path) -> str:
"""
从摘要文件中提取 TL;DR 部分。
"""
if not summary_file.exists():
raise FileNotFoundError(f"摘要文件未找到: {summary_file}")
with summary_file.open('r', encoding='utf-8') as f:
content = f.read()
# 使用正则表达式提取 ## TL;DR 部分
match = re.search(r'##\s+TL;DR\s+(.*?)\n##\s+', content, re.DOTALL)
if not match:
# 尝试匹配文件末尾
match = re.search(r'##\s+TL;DR\s+(.*)', content, re.DOTALL)
if not match:
raise ValueError(f"在 {summary_file} 中未找到 TL;DR 部分")
tldr = match.group(1).strip()
# 将多余的空白字符替换为单个空格
tldr = re.sub(r'\s+', ' ', tldr)
return tldr
def get_last_week_date_range():
"""
获取上周的开始和结束日期范围。
考虑到GitHub Actions运行在UTC时区,但我们需要UTC+8时区的日期范围。
"""
# 获取当前UTC时间
utc_now = datetime.now(timezone.utc)
# 转换为UTC+8时区
now_utc_plus_8 = utc_now.astimezone(UTC_PLUS_8)
today = now_utc_plus_8.date()
# 找到上周一(当前周的前一周的周一)
last_monday = today - timedelta(days=today.weekday() + 7)
# 找到上周日(当前周的前一周的周日)
last_sunday = last_monday + timedelta(days=6)
# 创建日期时间对象,使用UTC+8时区
start_datetime = datetime.combine(last_monday, datetime.min.time()).replace(tzinfo=UTC_PLUS_8)
end_datetime = datetime.combine(last_sunday, datetime.max.time()).replace(tzinfo=UTC_PLUS_8)
print(f"Current UTC time: {utc_now}")
print(f"Current UTC+8 time: {now_utc_plus_8}")
print(f"Date range: {start_datetime} to {end_datetime}")
return start_datetime, end_datetime
def main():
# 从环境变量获取 GitHub 令牌和仓库信息
github_token = os.getenv('GITHUB_TOKEN')
if not github_token:
raise EnvironmentError("环境变量 GITHUB_TOKEN 未设置")
github_repository = os.getenv('GITHUB_REPOSITORY') # 格式如 'owner/repo'
if not github_repository:
raise EnvironmentError("环境变量 GITHUB_REPOSITORY 未设置")
api_url = 'https://api.github.com'
# 检查是否为干运行模式
global DRY_RUN
dry_run_env = os.getenv('DRY_RUN', '').lower()
if dry_run_env in ('true', '1', 'yes'):
DRY_RUN = True
print("干运行模式已启用")
# 获取上周的日期范围
start_datetime, end_datetime = get_last_week_date_range()
# 读取 data.json
data_file = Path('data.json')
if not data_file.exists():
raise FileNotFoundError("未找到 data.json 文件")
with data_file.open('r', encoding='utf-8') as f:
data = json.load(f)
# 筛选上周内的条目
qualifying_entries = []
for entry in data:
timestamp = entry.get('timestamp')
if timestamp is None:
continue
# 将时间戳转换为UTC+8时区的datetime对象
entry_datetime = datetime.fromtimestamp(timestamp, tz=UTC_PLUS_8)
if start_datetime <= entry_datetime <= end_datetime:
qualifying_entries.append(entry)
print(f"Added entry: {entry.get('title')}")
if not qualifying_entries:
print("上周没有符合条件的条目,跳过发布。")
return
# 收集每个条目的 TL;DR
release_entries = []
for entry in qualifying_entries:
month = entry.get('month')
title = entry.get('title')
url = entry.get('url')
timestamp = entry.get('timestamp')
if not all([month, title, url, timestamp]):
continue
summary_file = Path(unquote(str(get_summary_file_path(title, timestamp, month=month, in_readme_md=True))))
try:
tldr = extract_tldr(summary_file)
except (FileNotFoundError, ValueError) as e:
print(f"处理 '{title}' 时出错: {e}")
tldr = "没有可用的 TL;DR。"
# 使用UTC+8时区格式化日期
date_str = datetime.fromtimestamp(timestamp, tz=UTC_PLUS_8).strftime('%Y-%m-%d')
# 构建摘要文件的链接
summary_path_str = str(summary_file).replace('\\', '/')
owner, repo = github_repository.split('/')
branch = os.getenv('GITHUB_REF_NAME', 'main') # 默认为 main 分支
# raw_url = f"https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{summary_path_str}"
raw_url = f"https://github.com/{owner}/{repo}/blob/{branch}/{summary_path_str}"
release_entries.append({
'date': date_str,
'title': title,
'link': raw_url,
'tldr': tldr
})
# 按日期排序
release_entries.sort(key=lambda x: x['date'])
# 构建发布内容
start_date_str = start_datetime.strftime('%Y-%m-%d')
end_date_str = end_datetime.strftime('%Y-%m-%d')
total = len(release_entries)
release_body = f"本周({start_date_str} - {end_date_str})共收藏了 {total} 篇文章。\n"
for idx, entry in enumerate(release_entries, start=1):
release_body += f"{idx}. ({entry['date']}) [{entry['title']}]({entry['link']}) - {entry['tldr']}\n"
print(release_body)
# 创建 GitHub Release
tag_name = f"weekly-{start_date_str}"
release_name = f"Weekly Read Articles ({start_date_str} - {end_date_str})"
if DRY_RUN:
print("\n=== DRY RUN MODE ===")
print(f"Would create tag: {tag_name}")
print(f"Would create release: {release_name}")
print(f"With {len(qualifying_entries)} entries")
print("No actual GitHub API calls will be made.")
return
# 检查标签是否已存在
tags_url = f"{api_url}/repos/{github_repository}/git/refs/tags/{tag_name}"
headers = {
'Authorization': f'token {github_token}',
'Accept': 'application/vnd.github.v3+json'
}
response = requests.get(tags_url, headers=headers)
if response.status_code == 200:
print(f"标签 '{tag_name}' 已存在,跳过发布。")
return
elif response.status_code != 404:
print(f"检查标签时出错: {response.status_code} {response.text}")
return
# 获取默认分支的最新提交 SHA
repo_url = f"{api_url}/repos/{github_repository}"
repo_resp = requests.get(repo_url, headers=headers)
if repo_resp.status_code != 200:
print(f"获取仓库信息时出错: {repo_resp.status_code} {repo_resp.text}")
return
repo_info = repo_resp.json()
default_branch = repo_info.get('default_branch', 'main')
branch_url = f"{api_url}/repos/{github_repository}/git/ref/heads/{default_branch}"
branch_resp = requests.get(branch_url, headers=headers)
if branch_resp.status_code != 200:
print(f"获取分支信息时出错: {branch_resp.status_code} {branch_resp.text}")
return
branch_info = branch_resp.json()
commit_sha = branch_info['object']['sha']
# 创建新的标签对象
tag_object = {
"tag": tag_name,
"message": release_name,
"object": commit_sha,
"type": "commit",
"tagger": {
"name": "GitHub Actions",
"email": "actions@github.com",
"date": datetime.utcnow().isoformat() + "Z" # 这里使用UTC时间是正确的,因为GitHub API要求ISO 8601格式的UTC时间
}
}
tag_resp = requests.post(f"{api_url}/repos/{github_repository}/git/tags", headers=headers, json=tag_object)
if tag_resp.status_code != 201:
print(f"创建标签对象时出错: {tag_resp.status_code} {tag_resp.text}")
return
tag_info = tag_resp.json()
tag_sha = tag_info['sha']
# 创建标签引用
ref_object = {
"ref": f"refs/tags/{tag_name}",
"sha": tag_sha
}
ref_resp = requests.post(f"{api_url}/repos/{github_repository}/git/refs", headers=headers, json=ref_object)
if ref_resp.status_code != 201:
print(f"创建标签引用时出错: {ref_resp.status_code} {ref_resp.text}")
return
# 创建发布
release_payload = {
"tag_name": tag_name,
"name": release_name,
"body": release_body,
"draft": False,
"prerelease": False
}
release_url = f"{api_url}/repos/{github_repository}/releases"
release_resp = requests.post(release_url, headers=headers, json=release_payload)
if release_resp.status_code != 201:
print(f"创建发布时出错: {release_resp.status_code} {release_resp.text}")
return
print(f"发布 '{release_name}' 创建成功。")
if __name__ == '__main__':
main()