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
+ api_url = f"https://api.github.com/repos/{ repo_path } /tags"
14
+
15
+ response = requests .get (api_url )
16
+
17
+ if response .status_code == 200 :
18
+ tags = response .json ()
19
+ if tags :
20
+ latest_tag = tags [0 ]['name' ]
21
+ print (f"Latest tag: { latest_tag } " )
22
+ return latest_tag
23
+ else :
24
+ print ("No tags found." )
25
+ return None
26
+ else :
27
+ print (f"Failed to fetch tags: { response .status_code } " )
28
+ return None
29
+
30
+
31
+ def get_local_tags () -> set [str ]:
32
+ result = subprocess .run (['git' , 'tag' ], stdout = subprocess .PIPE )
33
+ tags = result .stdout .decode ('utf-8' ).split ()
34
+ return set (tags )
35
+
36
+
37
+ def get_remote_tags (remote_name = 'origin' ) -> set [str ]:
38
+ result = subprocess .run (['git' , 'ls-remote' , '--tags' , remote_name ], stdout = subprocess .PIPE )
39
+ remote_tags_output = result .stdout .decode ('utf-8' )
40
+ remote_tags = set ()
41
+ for line in remote_tags_output .strip ().split ('\n ' ):
42
+ if line :
43
+ tag_ref = line .split ()[1 ]
44
+ if tag_ref .startswith ('refs/tags/' ):
45
+ remote_tags .add (tag_ref [len ('refs/tags/' ):])
46
+ return remote_tags
47
+
48
+
49
+ def delete_local_tag (tag ) -> None :
50
+ subprocess .run (['git' , 'tag' , '-d' , tag ], check = True )
51
+ print (f"Deleted local tag { tag } " )
52
+
53
+
54
+ def delete_remote_tag () -> None :
55
+ subprocess .run (['git' , 'fetch' , '--prune' , 'origin' , '+refs/tags/*:refs/tags/*' ], check = True )
56
+ local_tags = get_local_tags ()
57
+ remote_tags = get_remote_tags ()
58
+ tags_to_delete = local_tags - remote_tags
59
+
60
+ for tag in tags_to_delete :
61
+ delete_local_tag (tag )
62
+
63
+
64
+ # 处理只读文件删除问题的回调函数
65
+ def remove_readonly (func , path , _ ) -> None :
66
+ # os.chmod(path, stat.S_IWRITE)
67
+ subprocess .run (['attrib' , '-R' , path ], shell = True )
68
+ func (path )
69
+
70
+
71
+ # 删除文件夹
72
+ def delete_folder (folder_path ) -> None :
73
+ try :
74
+ if os .path .exists (folder_path ):
75
+ shutil .rmtree (folder_path , onerror = remove_readonly )
76
+ else :
77
+ print (f"文件夹 '{ folder_path } ' 不存在。" )
78
+ except Exception as exp :
79
+ print (f"文件夹 '{ folder_path } ' 删除失败。" )
80
+ print (exp )
81
+
82
+
83
+ def read_current_branch () -> str :
84
+ branches = os .popen ("git branch" ).read ().split ("\n " )
85
+ # 判断当前分支
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排序
95
+ tags = sorted ([tag .replace ("-preview" , "" ) for tag in tags if tag ], key = lambda x : tuple (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
+ # subprocess.run(['cd', '..'], check=True, shell=True)
102
+ current_path = os .getcwd ()
103
+ print ("当前路径: " + current_path )
104
+
105
+ username = "Star fire"
106
+
107
+ print ("用户名称: " + username )
108
+ print ("用户邮箱: " + email )
109
+
110
+ # 是否为preview版本
111
+ is_preview = True
112
+
113
+ # 忽略列表
114
+ ignore_list = [
115
+ ".chglog/*" ,
116
+ "*.yaml" ,
117
+ "*.yml" ,
118
+ ".github/API_USAGE/*" ,
119
+ ".github/ISSUE_TEMPLATE/*" ,
120
+ ".github/PULL_REQUEST_TEMPLATE/*" ,
121
+ ".github/Template/*" ,
122
+ ".github/workflows/*" ,
123
+ ".github/*.py" ,
124
+ ".github/*.sh" ,
125
+ ".github/*.bat" ,
126
+ ]
127
+
128
+ github = os .popen ("git remote get-url origin" ).read ().strip ()
129
+ print ("仓库地址: " + github )
130
+ current_branch = read_current_branch () # 读取当前分支
131
+ print ("仓库分支: " + current_branch )
132
+
133
+ steps = [
134
+ ("删除不存在的标签" , lambda : delete_remote_tag ()),
135
+ ]
136
+ for step_description , step_function in tqdm (steps , desc = "检查标签" ):
137
+ step_function ()
138
+
139
+ version = read_current_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 ["relatedPackages" ]["com.aio.package" ] = get_latest_github_tag ('https://github.com/AIO-GAME/Common.git' )
153
+ package ["version" ] = new_version
154
+ f .seek (0 )
155
+ json .dump (package , f , indent = 2 )
156
+ print ("写入新版本号成功: {0} -> {1}" .format (current_version , new_version ))
157
+ print ("写入依赖版本号成功: {0}" .format (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