1
+ import shutil
2
+ import time
3
+ import json
4
+ import os
5
+ import subprocess
6
+ from tqdm import tqdm
7
+ import requests
8
+
9
+
10
+ def get_latest_github_tag (repo_url ) -> str :
11
+ # 从仓库 URL 提取用户和仓库名称
12
+ repo_path = repo_url .split ("https://github.com/" )[1 ].replace (".git" , "" )
13
+ print (f"Fetching tags from { repo_path } " )
14
+ api_url = f"https://api.github.com/repos/{ repo_path } /tags"
15
+
16
+ response = requests .get (api_url , timeout = 10 )
17
+
18
+ if response .status_code == 200 :
19
+ tags = response .json ()
20
+ if tags :
21
+ latest_tag = tags [0 ]['name' ]
22
+ print (f"Latest tag: { latest_tag } " )
23
+ return latest_tag
24
+ else :
25
+ print ("No tags found." )
26
+ return None
27
+ else :
28
+ print (f"Failed to fetch tags: { response .status_code } " )
29
+ return None
30
+
31
+
32
+ def get_local_tags () -> set [str ]:
33
+ result = subprocess .run (['git' , 'tag' ], stdout = subprocess .PIPE )
34
+ tags = result .stdout .decode ('utf-8' ).split ()
35
+ return set (tags )
36
+
37
+
38
+ def get_remote_tags (remote_name = 'origin' ) -> set [str ]:
39
+ result = subprocess .run (['git' , 'ls-remote' , '--tags' , remote_name ], stdout = subprocess .PIPE )
40
+ remote_tags_output = result .stdout .decode ('utf-8' )
41
+ remote_tags = set ()
42
+ for line in remote_tags_output .strip ().split ('\n ' ):
43
+ if line :
44
+ tag_ref = line .split ()[1 ]
45
+ if tag_ref .startswith ('refs/tags/' ):
46
+ remote_tags .add (tag_ref [len ('refs/tags/' ):])
47
+ return remote_tags
48
+
49
+
50
+ def delete_local_tag (tag ) -> None :
51
+ subprocess .run (['git' , 'tag' , '-d' , tag ], check = True )
52
+ print (f"Deleted local tag { tag } " )
53
+
54
+
55
+ def delete_remote_tag () -> None :
56
+ subprocess .run (['git' , 'fetch' , '--prune' , 'origin' , '+refs/tags/*:refs/tags/*' ], check = True )
57
+ local_tags = get_local_tags ()
58
+ remote_tags = get_remote_tags ()
59
+ tags_to_delete = local_tags - remote_tags
60
+
61
+ for tag in tags_to_delete :
62
+ delete_local_tag (tag )
63
+
64
+
65
+ # 处理只读文件删除问题的回调函数
66
+ def remove_readonly (func , path , _ ) -> None :
67
+ # os.chmod(path, stat.S_IWRITE)
68
+ subprocess .run (['attrib' , '-R' , path ], shell = True )
69
+ func (path )
70
+
71
+
72
+ # 删除文件夹
73
+ def delete_folder (folder_path ) -> None :
74
+ try :
75
+ if os .path .exists (folder_path ):
76
+ shutil .rmtree (folder_path , onerror = remove_readonly )
77
+ else :
78
+ print (f"文件夹 '{ folder_path } ' 不存在。" )
79
+ except Exception as exp :
80
+ print (f"文件夹 '{ folder_path } ' 删除失败。" )
81
+ print (exp )
82
+
83
+
84
+ def read_current_branch () -> str : # 判断当前分支
85
+ branches = os .popen ("git branch" ).read ().split ("\n " )
86
+ for branch in branches :
87
+ if branch .startswith ("*" ):
88
+ return branch .replace ("* " , "" )
89
+
90
+
91
+ def read_current_version () -> str :
92
+ subprocess .run (['git' , 'fetch' , '--tags' ], check = True )
93
+ tags = os .popen ("git tag" ).read ().split ("\n " )
94
+ # 所有标签去掉空字符串 -preview标签去掉preview 然后按照version排序 1.2.3-preview -> 1.3.0-preview
95
+ tags = sorted ([tag .replace ("-preview" , "" ) for tag in tags if tag ], key = lambda x : list (map (int , x .split ("." ))))
96
+ return tags [- 1 ]
97
+
98
+
99
+ # 切换上一级目录
100
+ os .chdir (os .path .dirname (os .path .dirname (os .path .realpath (__file__ ))))
101
+ current_path = os .getcwd ()
102
+ print ("当前路径: " + current_path )
103
+
104
+ username = "Star fire"
105
+
106
+ print ("用户名称: " + username )
107
+ print ("用户邮箱: " + email )
108
+
109
+ # 是否为preview版本
110
+ is_preview = True
111
+
112
+ # 忽略列表
113
+ ignore_list = [
114
+ ".chglog/*" ,
115
+ "*.yaml" ,
116
+ "*.yml" ,
117
+ ".github/API_USAGE/*" ,
118
+ ".github/ISSUE_TEMPLATE/*" ,
119
+ ".github/PULL_REQUEST_TEMPLATE/*" ,
120
+ ".github/Template/*" ,
121
+ ".github/workflows/*" ,
122
+ ".github/*.py" ,
123
+ ".github/*.sh" ,
124
+ ".github/*.bat" ,
125
+ ]
126
+
127
+ github = os .popen ("git remote get-url origin" ).read ().strip ()
128
+ print ("仓库地址: " + github )
129
+ current_branch = read_current_branch () # 读取当前分支
130
+ print ("仓库分支: " + current_branch )
131
+
132
+ steps = [
133
+ ("删除不存在的标签" , lambda : delete_remote_tag ()),
134
+ ]
135
+ for step_description , step_function in tqdm (steps , desc = "检查标签" ):
136
+ step_function ()
137
+
138
+ version = read_current_version () # 读取当前版本号
139
+ print ("当前版本号: " + version )
140
+ # 递增版本号
141
+ version_list = version .split ("." )
142
+ if is_preview :
143
+ version_list [2 ] = str (int (version_list [2 ]) + 1 ) + "-preview"
144
+ else :
145
+ version_list [2 ] = str (int (version_list [2 ]) + 1 )
146
+ new_version = "." .join (version_list )
147
+
148
+ # 写入新版本号
149
+ with open ("package.json" , "r+" ) as f :
150
+ package = json .load (f )
151
+ current_version = package ["version" ]
152
+ package ["version" ] = new_version
153
+ package ["relatedPackages" ]["com.aio.package" ] = get_latest_github_tag ('https://github.com/AIO-GAME/Common.git' )
154
+ f .seek (0 )
155
+ json .dump (package , f , indent = 2 )
156
+ print ("写入配置: 版本号 {0} -> {1}" .format (current_version , new_version ))
157
+ print ("写入配置: 依赖库 {0} -> {1}" .format ("com.aio.package" , package ["relatedPackages" ]["com.aio.package" ]))
158
+ f .close ()
159
+
160
+ # 上传到远程仓库 捕获异常
161
+ if current_version != new_version :
162
+ try :
163
+ subprocess .run (['git' , 'pull' ], check = True )
164
+ subprocess .run (['git' , 'add' , 'package.json' ], check = True )
165
+ subprocess .run (['git' , 'commit' , '-m' , f"✨ up version { current_branch } -> { new_version } " ], check = True )
166
+ subprocess .run (['git' , 'push' , 'origin' , current_branch ], check = True )
167
+ print ("推送仓库: ({0})成功" .format (current_branch ))
168
+ except Exception as e :
169
+ print ("推送仓库: ({0})失败" .format (current_branch ))
170
+ print (e )
171
+
172
+ steps = [
173
+ ("设置用户名" ,
174
+ lambda : subprocess .run (['git' , 'config' , 'user.name' , username ], check = True , stdout = - 3 , stderr = - 3 )),
175
+ ("设置邮箱" ,
176
+ lambda : subprocess .run (['git' , 'config' , 'user.email' , email ], check = True , stdout = - 3 , stderr = - 3 )),
177
+ ("开启GPG签名" ,
178
+ lambda : subprocess .run (['git' , 'config' , 'commit.gpgSign' , 'true' ], check = True , stdout = - 3 , stderr = - 3 )),
179
+ ]
180
+ for step_description , step_function in tqdm (steps , desc = "设置环境" ):
181
+ step_function ()
182
+ # 克隆指定分支 到目标文件夹路径
183
+ os .chdir (os .path .dirname (current_path ))
184
+ new_branch_path = os .path .join (os .path .dirname (current_path ), new_version )
185
+ new_branch = "release/{0}_{1}" .format (new_version , str (int (time .time ())))
186
+
187
+ steps = []
188
+ if os .path .exists (new_branch_path ) is False :
189
+ steps .append (("克隆指定分支" ,
190
+ lambda : subprocess .run (['git' , 'clone' , github , '-b' , current_branch , '--single-branch' , new_branch_path ], check = True , stdout = - 3 , stderr = - 3 )))
191
+
192
+ # 切换环境变量路径 为指定分支路径
193
+ steps .append (("切换路径" , lambda : os .chdir (new_branch_path )))
194
+ steps .append (("重置分支" , lambda : subprocess .run (['git' , 'reset' , '--hard' ], check = True , stdout = - 3 , stderr = - 3 )))
195
+ steps .append (("拉取分支" , lambda : subprocess .run (['git' , 'pull' ], check = True , stdout = - 3 , stderr = - 3 )))
196
+ steps .append (("切换分支" , lambda : subprocess .run (['git' , 'checkout' , '-b' , new_branch ], check = True , stdout = - 3 , stderr = - 3 )))
197
+ for step_description , step_function in tqdm (steps , desc = "创建分支" , total = len (steps )):
198
+ step_function ()
199
+ print ("创建分支: {0}" .format (new_branch ))
200
+
201
+ # 在新的分支上忽略指定文件和文件夹 如果没有则创建 如果有则拼接
202
+ with open (os .path .join (new_branch_path , ".gitignore" ), "a+" ) as f :
203
+ for ignore in ignore_list :
204
+ if ignore .startswith ("*" ):
205
+ f .write (ignore + "\n " )
206
+ else :
207
+ f .write ("/" + ignore + "\n " )
208
+ print ("修改成功: .gitignore " )
209
+
210
+ # 删除指定文件和文件夹
211
+ errorList = []
212
+ for ignore in tqdm (ignore_list , desc = "删除列表" ):
213
+ try :
214
+ subprocess .run (['git' , 'rm' , '-r' , '--cached' , ignore ], check = True , stdout = - 3 , stderr = - 3 )
215
+ subprocess .run (['git' , 'clean' , '-fdx' , ignore ], check = True , stdout = - 3 , stderr = - 3 )
216
+ except subprocess .CalledProcessError as e :
217
+ errorList .append (ignore )
218
+
219
+ if len (errorList ) > 0 :
220
+ for error in errorList :
221
+ print ("删除失败: " + error )
222
+ else :
223
+ print ("删除成功" )
224
+
225
+ steps = [
226
+ ("删除标签" , lambda : delete_remote_tag ()),
227
+ ("设置用户名" ,
228
+ lambda : subprocess .run (['git' , 'config' , 'user.name' , username ], check = True , stdout = - 3 , stderr = - 3 )),
229
+ ("设置邮箱" ,
230
+ lambda : subprocess .run (['git' , 'config' , 'user.email' , email ], check = True , stdout = - 3 , stderr = - 3 )),
231
+ ("开启签名" ,
232
+ lambda : subprocess .run (['git' , 'config' , 'commit.gpgSign' , 'true' ], check = True , stdout = - 3 , stderr = - 3 )),
233
+ ("添加文件" ,
234
+ lambda : subprocess .run (['git' , 'add' , '.' ], check = True , stdout = - 3 , stderr = - 3 )),
235
+ ("提交文件" ,
236
+ lambda : subprocess .run (['git' , 'commit' , '-s' , '-m' , f"✨ up version { current_version } -> { new_version } " ], check = True , stdout = - 3 , stderr = - 3 )),
237
+ ("推送分支" ,
238
+ lambda : subprocess .run (['git' , 'push' , 'origin' , new_branch ], check = True , stdout = - 3 , stderr = - 3 )),
239
+ ("创建标签" ,
240
+ lambda : subprocess .run (['git' , 'tag' , '-s' , new_version , '-m' , f"✨ up version { current_version } -> { new_version } " ], check = True , stdout = - 3 , stderr = - 3 )),
241
+ ("推送标签" ,
242
+ lambda : subprocess .run (['git' , 'push' , 'origin' , new_version ], check = True , stdout = - 3 , stderr = - 3 )),
243
+ ("删除分支" ,
244
+ lambda : subprocess .run (['git' , 'push' , 'origin' , '--delete' , new_branch ], check = True , stdout = - 3 , stderr = - 3 )),
245
+ ("切换路径" , lambda : os .chdir (current_path )),
246
+ ("删除目标" , lambda : delete_folder (new_branch_path )),
247
+ ]
248
+ for step_description , step_function in tqdm (steps , desc = "上传标签" ):
249
+ step_function ()
250
+ print ("升级标签版本成功" )
0 commit comments