pindo 5.11.4 → 5.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/pindo/base/githelper.rb +16 -0
- data/lib/pindo/base/pindocontext.rb +13 -4
- data/lib/pindo/command/android/autobuild.rb +108 -185
- data/lib/pindo/command/android/build.rb +10 -2
- data/lib/pindo/command/ios/autobuild.rb +116 -213
- data/lib/pindo/command/ios/build.rb +12 -3
- data/lib/pindo/command/jps/upload.rb +253 -118
- data/lib/pindo/command/unity/autobuild.rb +297 -227
- data/lib/pindo/command/unity.rb +0 -3
- data/lib/pindo/command/utils/boss.rb +18 -15
- data/lib/pindo/command/utils/clearcert.rb +26 -18
- data/lib/pindo/command/utils/device.rb +28 -19
- data/lib/pindo/command/utils/feishu.rb +11 -4
- data/lib/pindo/command/utils/icon.rb +26 -20
- data/lib/pindo/command/utils/renewcert.rb +35 -29
- data/lib/pindo/command/utils/renewproj.rb +32 -25
- data/lib/pindo/command/utils/repoinit.rb +1 -1
- data/lib/pindo/command/utils/tag.rb +6 -180
- data/lib/pindo/command/utils/tgate.rb +34 -28
- data/lib/pindo/command/utils/xcassets.rb +30 -20
- data/lib/pindo/command/web/autobuild.rb +148 -128
- data/lib/pindo/module/android/android_build_helper.rb +0 -6
- data/lib/pindo/module/android/android_config_helper.rb +4 -26
- data/lib/pindo/module/build/build_helper.rb +18 -294
- data/lib/pindo/module/build/git_repo_helper.rb +530 -0
- data/lib/pindo/module/build/icon_downloader.rb +85 -0
- data/lib/pindo/module/pgyer/pgyerhelper.rb +16 -11
- data/lib/pindo/module/task/model/build/android_dev_build_task.rb +209 -0
- data/lib/pindo/module/task/model/build/android_release_build_task.rb +29 -0
- data/lib/pindo/module/task/model/build/ios_adhoc_build_task.rb +53 -0
- data/lib/pindo/module/task/model/build/ios_dev_build_task.rb +251 -0
- data/lib/pindo/module/task/model/build/ios_release_build_task.rb +53 -0
- data/lib/pindo/module/task/model/build/web_dev_build_task.rb +43 -0
- data/lib/pindo/module/task/model/build_task.rb +125 -301
- data/lib/pindo/module/task/model/git_tag_task.rb +80 -0
- data/lib/pindo/module/task/model/unity_export_task.rb +53 -41
- data/lib/pindo/module/task/model/upload_task.rb +149 -208
- data/lib/pindo/module/task/pindo_task.rb +135 -95
- data/lib/pindo/module/task/task_manager.rb +202 -352
- data/lib/pindo/module/unity/unity_helper.rb +7 -3
- data/lib/pindo/module/xcode/xcode_build_config.rb +4 -10
- data/lib/pindo/module/xcode/xcode_build_helper.rb +19 -0
- data/lib/pindo/version.rb +1 -1
- metadata +10 -4
- data/lib/pindo/command/unity/apk.rb +0 -185
- data/lib/pindo/command/unity/ipa.rb +0 -198
- data/lib/pindo/command/unity/web.rb +0 -163
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
require 'pindo/base/githelper'
|
|
3
|
+
require 'pindo/base/executable'
|
|
4
|
+
require 'pindo/base/pindocontext'
|
|
5
|
+
require 'highline/import'
|
|
6
|
+
|
|
7
|
+
module Pindo
|
|
8
|
+
class GitRepoHelper
|
|
9
|
+
include Singleton
|
|
10
|
+
include Pindo::Githelper
|
|
11
|
+
|
|
12
|
+
attr_accessor :temp_tag_decision
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def share_instance
|
|
16
|
+
instance
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# 主入口函数 - 创建并推送 Git 标签
|
|
21
|
+
# @param project_dir [String] 项目目录
|
|
22
|
+
# @param mode [String] 版本号增加模式 (major/minor/patch)
|
|
23
|
+
# @param force_retag [Boolean] 是否强制重新打tag
|
|
24
|
+
# @param custom_tag [String] 自定义tag版本号
|
|
25
|
+
# @param release_branch [String] 发布分支名称,默认为 'master'
|
|
26
|
+
def create_and_push_tag(project_dir:, mode: 'minor', force_retag: false, custom_tag: nil, release_branch: 'master')
|
|
27
|
+
puts project_dir
|
|
28
|
+
|
|
29
|
+
# 1. 验证 Git 仓库
|
|
30
|
+
unless is_git_directory?(local_repo_dir: project_dir)
|
|
31
|
+
raise Informative, "当前目录不是git仓库,请在git仓库目录下执行此命令"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# 获取git仓库根目录
|
|
35
|
+
root_dir = git_root_directory(local_repo_dir: project_dir)
|
|
36
|
+
if root_dir.nil?
|
|
37
|
+
raise Informative, "无法获取git仓库根目录"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# 2. 处理未提交的文件
|
|
41
|
+
process_need_add_files(project_dir: root_dir)
|
|
42
|
+
|
|
43
|
+
# 3. 获取当前分支
|
|
44
|
+
current_branch = git!(%W(-C #{root_dir} rev-parse --abbrev-ref HEAD)).strip
|
|
45
|
+
coding_branch = current_branch
|
|
46
|
+
|
|
47
|
+
# 4. 合并到发布分支
|
|
48
|
+
Funlog.instance.fancyinfo_start("开始合并到#{release_branch}分支")
|
|
49
|
+
merge_to_release_branch(
|
|
50
|
+
project_dir: root_dir,
|
|
51
|
+
release_branch: release_branch,
|
|
52
|
+
coding_branch: coding_branch
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# 5. 添加版本标签并返回 tag 名称
|
|
56
|
+
new_tag = add_release_tag(
|
|
57
|
+
project_dir: root_dir,
|
|
58
|
+
increment_mode: mode,
|
|
59
|
+
force_retag: force_retag,
|
|
60
|
+
custom_tag: custom_tag
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
new_tag
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# 检查并安装 git-cliff
|
|
67
|
+
# @param project_path [String] 项目路径
|
|
68
|
+
def check_check_and_install_cliff(project_path)
|
|
69
|
+
if is_git_directory?(local_repo_dir: project_path)
|
|
70
|
+
current_git_root_path = git_root_directory(local_repo_dir: project_path)
|
|
71
|
+
unless File.exist?(File.join(current_git_root_path, 'cliff.toml'))
|
|
72
|
+
add_git_cliffconfig(current_git_root_path)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
begin
|
|
77
|
+
if !system('which git-cliff > /dev/null 2>&1')
|
|
78
|
+
puts "安装git-cliff..."
|
|
79
|
+
install_gitcliff()
|
|
80
|
+
end
|
|
81
|
+
rescue
|
|
82
|
+
Funlog.instance.fancyinfo_error("安装git-cliff出现错误")
|
|
83
|
+
return
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# 写入 .gitignore 文件
|
|
88
|
+
# @param git_root_dir [String] Git 根目录
|
|
89
|
+
def write_gitignore(git_root_dir)
|
|
90
|
+
gitignore_path = File.join(git_root_dir, '.gitignore')
|
|
91
|
+
|
|
92
|
+
# 定义要添加的gitignore规则数组
|
|
93
|
+
ignore_rules = [
|
|
94
|
+
'Temp',
|
|
95
|
+
'Logs',
|
|
96
|
+
'build_ios.log',
|
|
97
|
+
'feishu.json',
|
|
98
|
+
'CHANGELOG.md',
|
|
99
|
+
'GoodPlatform/iOS/*',
|
|
100
|
+
'GoodPlatform/Android/*',
|
|
101
|
+
'GoodPlatform/BaseiOS/Unity/*',
|
|
102
|
+
'GoodPlatform/BaseiOS/Pods/',
|
|
103
|
+
'GoodPlatform/BaseiOS/build',
|
|
104
|
+
'GoodPlatform/BaseiOS/config.json',
|
|
105
|
+
'GoodPlatform/BaseiOS/Podfile.lock',
|
|
106
|
+
'GoodPlatform/BaseAndroid/Unity/*',
|
|
107
|
+
'GoodPlatform/BaseAndroid/build',
|
|
108
|
+
'GoodPlatform/WebGL',
|
|
109
|
+
'config.json',
|
|
110
|
+
'Assets/Packages',
|
|
111
|
+
'Assets/WebGLTemplates.meta',
|
|
112
|
+
'Assets/WebGLTemplates/',
|
|
113
|
+
'Packages/packages-lock.json'
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
# 读取现有的gitignore内容
|
|
117
|
+
existing_lines = []
|
|
118
|
+
if File.exist?(gitignore_path)
|
|
119
|
+
existing_lines = File.readlines(gitignore_path).map(&:strip)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# 过滤出需要添加的规则(不存在的)
|
|
123
|
+
rules_to_add = ignore_rules.reject { |rule| existing_lines.include?(rule) }
|
|
124
|
+
|
|
125
|
+
# 如果有需要添加的规则,则添加
|
|
126
|
+
unless rules_to_add.empty?
|
|
127
|
+
File.open(gitignore_path, 'a') do |f|
|
|
128
|
+
# 检查是否已有Pindo标记,如果没有则添加
|
|
129
|
+
pindo_marker = '# Added by Pindo (pindo_common_ignore_1.0.0)'
|
|
130
|
+
f.puts("\n#{pindo_marker}") unless existing_lines.include?(pindo_marker.strip)
|
|
131
|
+
|
|
132
|
+
# 添加每条新规则
|
|
133
|
+
rules_to_add.each do |rule|
|
|
134
|
+
f.puts(rule)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# 添加 git-cliff 配置
|
|
141
|
+
# @param project_path [String] 项目路径
|
|
142
|
+
def add_git_cliffconfig(project_path)
|
|
143
|
+
temp_dir = Dir.pwd
|
|
144
|
+
Funlog.instance.fancyinfo_start("添加日志变更git-cliff配置...")
|
|
145
|
+
if is_git_directory?(local_repo_dir: project_path)
|
|
146
|
+
current_git_root_path = git_root_directory(local_repo_dir: project_path)
|
|
147
|
+
Dir.chdir(current_git_root_path)
|
|
148
|
+
pindo_common_dir = clone_pindo_common_config_repo(force_delete:false)
|
|
149
|
+
if File.exist?(File.join(pindo_common_dir, 'cliff.toml'))
|
|
150
|
+
FileUtils.cp_r(File.join(pindo_common_dir, 'cliff.toml'), File.join(current_git_root_path, 'cliff.toml'))
|
|
151
|
+
end
|
|
152
|
+
Funlog.instance.fancyinfo_update("仓库添加git-cliff配置")
|
|
153
|
+
write_gitignore(current_git_root_path)
|
|
154
|
+
Funlog.instance.fancyinfo_update("仓库添加.gitignore")
|
|
155
|
+
Dir.chdir(current_git_root_path)
|
|
156
|
+
current_branch = git!(%W(-C #{current_git_root_path} rev-parse --abbrev-ref HEAD)).strip
|
|
157
|
+
git!(%W(-C #{current_git_root_path} add cliff.toml))
|
|
158
|
+
git!(%W(-C #{current_git_root_path} add .gitignore))
|
|
159
|
+
commit_message = "docs: 添加日志变更配置".encode('UTF-8')
|
|
160
|
+
git!(%W(-C #{current_git_root_path} commit -m #{commit_message}))
|
|
161
|
+
git!(%W(-C #{current_git_root_path} push origin #{current_branch}))
|
|
162
|
+
else
|
|
163
|
+
Funlog.instance.fancyinfo_error("当前目录不是git仓库,请在git仓库根目录下执行此命令")
|
|
164
|
+
Dir.chdir(temp_dir)
|
|
165
|
+
return
|
|
166
|
+
end
|
|
167
|
+
Funlog.instance.fancyinfo_success("日志变更git-cliff配置完成!")
|
|
168
|
+
Dir.chdir(temp_dir)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# 安装 git-cliff
|
|
172
|
+
def install_gitcliff
|
|
173
|
+
puts "\n检查git-cliff命令是否安装"
|
|
174
|
+
begin
|
|
175
|
+
if !system('which git-cliff > /dev/null 2>&1')
|
|
176
|
+
system('bash -c "$(curl -fsSL https://gitee.com/goodtools/env/raw/master/gitcliff_install.sh)"')
|
|
177
|
+
end
|
|
178
|
+
rescue
|
|
179
|
+
Funlog.instance.fancyinfo_error("安装git-cliff出现错误")
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# 检查是否需要添加 Git 标签
|
|
184
|
+
# @param project_path [String] 项目路径
|
|
185
|
+
# @param auto_mode [Boolean] 是否自动模式
|
|
186
|
+
# @return [Array<Boolean, Array>] [是否需要添加tag, tag参数]
|
|
187
|
+
def check_is_need_add_tag?(project_path, auto_mode: false)
|
|
188
|
+
tag_action_parms = nil
|
|
189
|
+
is_need_add_tag = false
|
|
190
|
+
|
|
191
|
+
if is_git_directory?(local_repo_dir: project_path)
|
|
192
|
+
current_git_root_path = git_root_directory(local_repo_dir: project_path)
|
|
193
|
+
latest_tag = get_latest_version_tag(project_dir: current_git_root_path)
|
|
194
|
+
|
|
195
|
+
# 检查是否需要打 tag:
|
|
196
|
+
# 1. 最新 tag 不在 HEAD 上,或者
|
|
197
|
+
# 2. 仓库有未提交的更改
|
|
198
|
+
tag_not_at_head = !is_tag_at_head?(git_root_dir: current_git_root_path, tag_name: latest_tag)
|
|
199
|
+
has_uncommitted = has_uncommitted_changes?(git_root_dir: current_git_root_path)
|
|
200
|
+
|
|
201
|
+
if tag_not_at_head || has_uncommitted
|
|
202
|
+
# 提示用户需要打 tag 的原因
|
|
203
|
+
if has_uncommitted && !tag_not_at_head
|
|
204
|
+
puts "\n注意:仓库有未提交的更改,建议提交后再打 Tag"
|
|
205
|
+
end
|
|
206
|
+
# 检查环境变量
|
|
207
|
+
env_tag_decision = ENV['PINDO_TAG_DECISION']
|
|
208
|
+
if env_tag_decision && !env_tag_decision.empty?
|
|
209
|
+
case env_tag_decision.downcase
|
|
210
|
+
when 'new', 'new_tag', '1'
|
|
211
|
+
puts "\n环境变量指定:新增版本号,打新Tag"
|
|
212
|
+
puts
|
|
213
|
+
tag_action_parms = []
|
|
214
|
+
is_need_add_tag = true
|
|
215
|
+
# 保存到缓存
|
|
216
|
+
context = PindoContext.instance
|
|
217
|
+
decision = {
|
|
218
|
+
tag_action_parms: tag_action_parms,
|
|
219
|
+
is_need_add_tag: is_need_add_tag,
|
|
220
|
+
action: :new_tag,
|
|
221
|
+
description: "新增版本号,打新Tag"
|
|
222
|
+
}
|
|
223
|
+
context.set_selection(PindoContext::SelectionKey::TAG_DECISION, decision)
|
|
224
|
+
return is_need_add_tag, tag_action_parms
|
|
225
|
+
when 'retag', 'recreate', '2'
|
|
226
|
+
puts "\n环境变量指定:将上次的Tag删除重新打Tag"
|
|
227
|
+
puts
|
|
228
|
+
tag_action_parms = ['--retag']
|
|
229
|
+
is_need_add_tag = true
|
|
230
|
+
# 保存到缓存
|
|
231
|
+
context = PindoContext.instance
|
|
232
|
+
decision = {
|
|
233
|
+
tag_action_parms: tag_action_parms,
|
|
234
|
+
is_need_add_tag: is_need_add_tag,
|
|
235
|
+
action: :recreate_tag,
|
|
236
|
+
description: "将上次的Tag删除重新打Tag"
|
|
237
|
+
}
|
|
238
|
+
context.set_selection(PindoContext::SelectionKey::TAG_DECISION, decision)
|
|
239
|
+
return is_need_add_tag, tag_action_parms
|
|
240
|
+
when 'skip', 'no', 'none', '3'
|
|
241
|
+
puts "\n环境变量指定:不需要Tag继续编译"
|
|
242
|
+
puts
|
|
243
|
+
tag_action_parms = nil
|
|
244
|
+
is_need_add_tag = false
|
|
245
|
+
# 保存到缓存
|
|
246
|
+
context = PindoContext.instance
|
|
247
|
+
decision = {
|
|
248
|
+
tag_action_parms: tag_action_parms,
|
|
249
|
+
is_need_add_tag: is_need_add_tag,
|
|
250
|
+
action: :continue_without_tag,
|
|
251
|
+
description: "不需要Tag继续编译且上传"
|
|
252
|
+
}
|
|
253
|
+
context.set_selection(PindoContext::SelectionKey::TAG_DECISION, decision)
|
|
254
|
+
return is_need_add_tag, tag_action_parms
|
|
255
|
+
when 'exit', 'quit', '4'
|
|
256
|
+
Funlog.instance.fancyinfo_error("环境变量指定:终止退出编译!")
|
|
257
|
+
return false, nil
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
if auto_mode
|
|
262
|
+
# 在自动化模式或没有交互式终端时,默认选择新增版本号打新Tag
|
|
263
|
+
puts "检测到当前代码没有打Tag,在自动模式下将自动新增版本号并打新Tag"
|
|
264
|
+
tag_action_parms = []
|
|
265
|
+
is_need_add_tag = true
|
|
266
|
+
else
|
|
267
|
+
# 检查是否已有用户选择
|
|
268
|
+
context = PindoContext.instance
|
|
269
|
+
# 优先从持久化缓存读取,如果没有则从内存临时缓存读取
|
|
270
|
+
cached_decision = context.get_selection(PindoContext::SelectionKey::TAG_DECISION)
|
|
271
|
+
|
|
272
|
+
# 只有当持久化缓存中确实不存在该键时,才从临时缓存读取
|
|
273
|
+
if cached_decision.nil? && !context.has_selection?(PindoContext::SelectionKey::TAG_DECISION)
|
|
274
|
+
# 从 GitRepoHelper 的临时缓存读取
|
|
275
|
+
cached_decision = self.temp_tag_decision
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
if cached_decision && cached_decision.is_a?(Hash)
|
|
279
|
+
# 使用之前的选择
|
|
280
|
+
puts "\n使用之前的选择:#{cached_decision[:description]}"
|
|
281
|
+
tag_action_parms = cached_decision[:tag_action_parms]
|
|
282
|
+
is_need_add_tag = cached_decision[:is_need_add_tag]
|
|
283
|
+
|
|
284
|
+
# 如果是退出选择,则返回
|
|
285
|
+
if cached_decision[:action] == :exit
|
|
286
|
+
Funlog.instance.fancyinfo_error("终止退出编译!")
|
|
287
|
+
return false, nil
|
|
288
|
+
end
|
|
289
|
+
else
|
|
290
|
+
# 第一次询问
|
|
291
|
+
cli = HighLine.new
|
|
292
|
+
selected_action = nil
|
|
293
|
+
selected_description = nil
|
|
294
|
+
|
|
295
|
+
menu_options = {
|
|
296
|
+
"新增版本号,打新Tag" => -> {
|
|
297
|
+
tag_action_parms = []
|
|
298
|
+
selected_action = :new_tag
|
|
299
|
+
selected_description = "新增版本号,打新Tag"
|
|
300
|
+
is_need_add_tag = true
|
|
301
|
+
:new_tag
|
|
302
|
+
},
|
|
303
|
+
"将上次的Tag删除重新打Tag" => -> {
|
|
304
|
+
tag_action_parms = []
|
|
305
|
+
tag_action_parms << "--retag"
|
|
306
|
+
selected_action = :recreate_tag
|
|
307
|
+
selected_description = "将上次的Tag删除重新打Tag"
|
|
308
|
+
is_need_add_tag = true
|
|
309
|
+
:recreate_tag
|
|
310
|
+
},
|
|
311
|
+
"不需要Tag继续编译且上传,手动修改上传备注" => -> {
|
|
312
|
+
puts ""
|
|
313
|
+
tag_action_parms = nil
|
|
314
|
+
selected_action = :continue_without_tag
|
|
315
|
+
selected_description = "不需要Tag继续编译且上传"
|
|
316
|
+
is_need_add_tag = false
|
|
317
|
+
:continue_without_tag
|
|
318
|
+
},
|
|
319
|
+
"终止退出编译" => -> {
|
|
320
|
+
tag_action_parms = nil
|
|
321
|
+
selected_action = :exit
|
|
322
|
+
selected_description = "终止退出编译"
|
|
323
|
+
is_need_add_tag = false
|
|
324
|
+
Funlog.instance.fancyinfo_error("终止退出编译!")
|
|
325
|
+
:exit
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
result = cli.choose do |menu|
|
|
330
|
+
menu.header = "当前代码并没有打Tag,上传的Changelog需要Tag"
|
|
331
|
+
menu.prompt = "请选中打Tag的方式, 请输入选项(1/2/3...):"
|
|
332
|
+
menu_options.each do |option, action|
|
|
333
|
+
menu.choice(option) { action.call }
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# 如果选择退出,直接返回
|
|
338
|
+
return false, nil if selected_action == :exit
|
|
339
|
+
|
|
340
|
+
# 保存用户选择
|
|
341
|
+
# 只有选择"新增版本号,打新Tag"时才保存到持久化缓存
|
|
342
|
+
if selected_action == :new_tag
|
|
343
|
+
# 保存到持久化缓存(文件)
|
|
344
|
+
context.set_selection(PindoContext::SelectionKey::TAG_DECISION, {
|
|
345
|
+
action: selected_action,
|
|
346
|
+
description: selected_description,
|
|
347
|
+
tag_action_parms: tag_action_parms,
|
|
348
|
+
is_need_add_tag: is_need_add_tag
|
|
349
|
+
})
|
|
350
|
+
# 清除临时缓存
|
|
351
|
+
self.temp_tag_decision = nil
|
|
352
|
+
else
|
|
353
|
+
# 不清空持久化缓存(避免将 nil 写入文件)
|
|
354
|
+
# 只使用临时缓存(仅在内存中,不会写入文件)
|
|
355
|
+
self.temp_tag_decision = {
|
|
356
|
+
action: selected_action,
|
|
357
|
+
description: selected_description,
|
|
358
|
+
tag_action_parms: tag_action_parms,
|
|
359
|
+
is_need_add_tag: is_need_add_tag
|
|
360
|
+
}
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
return [is_need_add_tag, tag_action_parms]
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
private
|
|
371
|
+
|
|
372
|
+
# 添加版本标签
|
|
373
|
+
# @param project_dir [String] 项目目录
|
|
374
|
+
# @param increment_mode [String] 版本号增加模式 (major/minor/patch)
|
|
375
|
+
# @param force_retag [Boolean] 是否强制重新打tag
|
|
376
|
+
# @param custom_tag [String] 自定义tag版本号
|
|
377
|
+
def add_release_tag(project_dir:, increment_mode: "minor", force_retag: false, custom_tag: nil)
|
|
378
|
+
raise ArgumentError, "项目目录不能为空" if project_dir.nil?
|
|
379
|
+
|
|
380
|
+
# 如果指定了自定义tag,直接使用
|
|
381
|
+
if custom_tag && !custom_tag.empty?
|
|
382
|
+
Funlog.instance.fancyinfo_start("使用指定的tag版本: #{custom_tag}")
|
|
383
|
+
|
|
384
|
+
# 确保tag有v前缀
|
|
385
|
+
new_tag = custom_tag.start_with?('v') ? custom_tag : "v#{custom_tag}"
|
|
386
|
+
|
|
387
|
+
# 检查tag是否已存在
|
|
388
|
+
existing_tags = git!(%W(-C #{project_dir} tag -l)).split("\n")
|
|
389
|
+
if existing_tags.include?(new_tag)
|
|
390
|
+
if force_retag
|
|
391
|
+
Funlog.instance.fancyinfo_update("tag #{new_tag} 已存在,强制重新打tag")
|
|
392
|
+
git!(%W(-C #{project_dir} tag -d #{new_tag}))
|
|
393
|
+
git!(%W(-C #{project_dir} push origin :refs/tags/#{new_tag}))
|
|
394
|
+
else
|
|
395
|
+
Funlog.instance.fancyinfo_success("tag #{new_tag} 已存在")
|
|
396
|
+
Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
|
|
397
|
+
return new_tag # 返回已存在的 tag
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# 创建tag并推送
|
|
402
|
+
git!(%W(-C #{project_dir} tag #{new_tag}))
|
|
403
|
+
git!(%W(-C #{project_dir} push origin #{new_tag}))
|
|
404
|
+
|
|
405
|
+
Funlog.instance.fancyinfo_success("创建tag: #{new_tag}")
|
|
406
|
+
Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
|
|
407
|
+
return new_tag # 返回新创建的 tag
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# 原有的自动递增逻辑
|
|
411
|
+
Funlog.instance.fancyinfo_start("开始创建初tag")
|
|
412
|
+
latest_tag = get_latest_version_tag(project_dir: project_dir)
|
|
413
|
+
if latest_tag.nil?
|
|
414
|
+
new_tag = create_next_version_tag(
|
|
415
|
+
project_dir: project_dir,
|
|
416
|
+
tag_prefix: "v",
|
|
417
|
+
increment_mode: increment_mode,
|
|
418
|
+
force_retag: false
|
|
419
|
+
)
|
|
420
|
+
Funlog.instance.fancyinfo_success("创建初始tag: #{new_tag}")
|
|
421
|
+
Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
|
|
422
|
+
return new_tag # 返回初始 tag
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
if is_tag_at_head?(git_root_dir: project_dir, tag_name: latest_tag)
|
|
426
|
+
Funlog.instance.fancyinfo_success("当前commit已有tag: #{latest_tag},无需重新打tag")
|
|
427
|
+
Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
|
|
428
|
+
return latest_tag # 返回已存在的 tag
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
Funlog.instance.fancyinfo_success("最近的上次tag是: #{latest_tag} ")
|
|
432
|
+
new_tag = create_next_version_tag(
|
|
433
|
+
project_dir: project_dir,
|
|
434
|
+
tag_prefix: "v",
|
|
435
|
+
increment_mode: increment_mode,
|
|
436
|
+
force_retag: force_retag
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
Funlog.instance.fancyinfo_success("当前仓库的tag: #{new_tag}")
|
|
440
|
+
Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
|
|
441
|
+
|
|
442
|
+
new_tag # 返回新创建的 tag
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
# 合并到发布分支
|
|
446
|
+
# @param project_dir [String] 项目目录
|
|
447
|
+
# @param release_branch [String] 发布分支名称
|
|
448
|
+
# @param coding_branch [String] 当前开发分支名称
|
|
449
|
+
def merge_to_release_branch(project_dir:, release_branch:, coding_branch:)
|
|
450
|
+
current_project_dir = project_dir
|
|
451
|
+
Funlog.instance.fancyinfo_start("开始合并到#{release_branch}分支")
|
|
452
|
+
if !coding_branch.eql?(release_branch)
|
|
453
|
+
coding_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{coding_branch})).strip
|
|
454
|
+
release_branch_commit_id = nil
|
|
455
|
+
|
|
456
|
+
if remote_branch_exists?(local_repo_dir: current_project_dir, branch: release_branch)
|
|
457
|
+
Funlog.instance.fancyinfo_update("存在#{release_branch}远程分支")
|
|
458
|
+
if local_branch_exists?(local_repo_dir: current_project_dir, branch: release_branch)
|
|
459
|
+
Funlog.instance.fancyinfo_update("存在#{release_branch}本地分支")
|
|
460
|
+
git!(%W(-C #{current_project_dir} checkout #{release_branch}))
|
|
461
|
+
else
|
|
462
|
+
Funlog.instance.fancyinfo_update("不存在#{release_branch}本地分支")
|
|
463
|
+
git!(%W(-C #{current_project_dir} checkout -b #{release_branch} origin/#{release_branch}))
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
git!(%W(-C #{current_project_dir} branch --set-upstream-to=origin/#{release_branch} #{release_branch}))
|
|
467
|
+
git!(%W(-C #{current_project_dir} fetch origin #{release_branch}))
|
|
468
|
+
git!(%W(-C #{current_project_dir} merge origin/#{release_branch}))
|
|
469
|
+
|
|
470
|
+
# 执行合并操作,捕获输出以便后续检查冲突
|
|
471
|
+
stdout, exit_status = Executable.capture_command('git', %W(-C #{current_project_dir} merge #{coding_branch}), :capture => :out)
|
|
472
|
+
|
|
473
|
+
# 检查是否有冲突(git merge 在有冲突时返回非0状态)
|
|
474
|
+
conflict_filelist = git!(%W(-C #{current_project_dir} diff --name-only --diff-filter=U --relative))
|
|
475
|
+
if !conflict_filelist.nil? && conflict_filelist.size > 0
|
|
476
|
+
puts "合并代码冲突, 冲突文件如下:"
|
|
477
|
+
raise Informative, "请手动处理冲突的文件!!!"
|
|
478
|
+
else
|
|
479
|
+
git!(%W(-C #{current_project_dir} push))
|
|
480
|
+
Funlog.instance.fancyinfo_success("代码已经合并到#{release_branch}分支")
|
|
481
|
+
# 获取 release_branch 的 commit ID(处理空分支情况)
|
|
482
|
+
begin
|
|
483
|
+
release_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{release_branch})).strip
|
|
484
|
+
rescue => e
|
|
485
|
+
# 分支可能存在但没有提交(空分支),此时使用 coding_branch 的 commit
|
|
486
|
+
Funlog.instance.fancyinfo_update("#{release_branch}分支为空或获取commit失败,将使用当前分支commit")
|
|
487
|
+
release_branch_commit_id = coding_branch_commit_id
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
else
|
|
492
|
+
if local_branch_exists?(local_repo_dir: current_project_dir, branch: release_branch)
|
|
493
|
+
Funlog.instance.fancyinfo_update("不存在#{release_branch}远程分支")
|
|
494
|
+
Funlog.instance.fancyinfo_update("存在#{release_branch}本地分支")
|
|
495
|
+
git!(%W(-C #{current_project_dir} checkout #{release_branch}))
|
|
496
|
+
git!(%W(-C #{current_project_dir} checkout -b #{release_branch}_temp))
|
|
497
|
+
git!(%W(-C #{current_project_dir} checkout #{coding_branch}))
|
|
498
|
+
git!(%W(-C #{current_project_dir} branch -D #{release_branch}))
|
|
499
|
+
else
|
|
500
|
+
Funlog.instance.fancyinfo_update("不存在#{release_branch}远程分支")
|
|
501
|
+
Funlog.instance.fancyinfo_update("不存在#{release_branch}本地分支")
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
git!(%W(-C #{current_project_dir} checkout -b #{release_branch}))
|
|
505
|
+
git!(%W(-C #{current_project_dir} push origin #{release_branch}))
|
|
506
|
+
git!(%W(-C #{current_project_dir} branch --set-upstream-to=origin/#{release_branch} #{release_branch}))
|
|
507
|
+
|
|
508
|
+
Funlog.instance.fancyinfo_success("代码已经合并到#{release_branch}分支")
|
|
509
|
+
# 获取 release_branch 的 commit ID(处理空分支情况)
|
|
510
|
+
begin
|
|
511
|
+
release_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{release_branch})).strip
|
|
512
|
+
rescue => e
|
|
513
|
+
# 新创建的分支,commit ID 应该与 coding_branch 相同
|
|
514
|
+
release_branch_commit_id = coding_branch_commit_id
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
git!(%W(-C #{current_project_dir} checkout #{coding_branch}))
|
|
519
|
+
if release_branch_commit_id && !release_branch_commit_id.eql?(coding_branch_commit_id)
|
|
520
|
+
git!(%W(-C #{current_project_dir} merge #{release_branch}))
|
|
521
|
+
Funlog.instance.fancyinfo_success("已将#{release_branch}合并到#{coding_branch}")
|
|
522
|
+
end
|
|
523
|
+
git!(%W(-C #{current_project_dir} push origin #{coding_branch}))
|
|
524
|
+
Funlog.instance.fancyinfo_success("已推送#{coding_branch}分支到远程")
|
|
525
|
+
else
|
|
526
|
+
Funlog.instance.fancyinfo_success("代码处于#{coding_branch}分支,无需合并")
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'open-uri'
|
|
2
|
+
require 'openssl'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Pindo
|
|
6
|
+
module IconDownloader
|
|
7
|
+
# 带重试机制的文件下载
|
|
8
|
+
# @param url [String] 下载URL
|
|
9
|
+
# @param save_path [String] 保存路径
|
|
10
|
+
# @param max_retries [Integer] 最大重试次数,默认3次
|
|
11
|
+
# @param retry_delay [Integer] 重试间隔秒数,默认2秒
|
|
12
|
+
# @param options [Hash] URI.open 的选项
|
|
13
|
+
# @return [Boolean] 是否下载成功
|
|
14
|
+
def self.download_file_with_retry(url:, save_path:, max_retries: 3, retry_delay: 2, options: {})
|
|
15
|
+
return false if url.nil? || url.empty?
|
|
16
|
+
return false if save_path.nil? || save_path.empty?
|
|
17
|
+
|
|
18
|
+
# 默认选项
|
|
19
|
+
default_options = {
|
|
20
|
+
read_timeout: 30,
|
|
21
|
+
open_timeout: 10,
|
|
22
|
+
redirect: true,
|
|
23
|
+
ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE
|
|
24
|
+
}
|
|
25
|
+
merged_options = default_options.merge(options)
|
|
26
|
+
|
|
27
|
+
# 确保目录存在
|
|
28
|
+
save_dir = File.dirname(save_path)
|
|
29
|
+
FileUtils.mkdir_p(save_dir) unless File.exist?(save_dir)
|
|
30
|
+
|
|
31
|
+
attempt = 0
|
|
32
|
+
last_error = nil
|
|
33
|
+
|
|
34
|
+
while attempt < max_retries
|
|
35
|
+
attempt += 1
|
|
36
|
+
begin
|
|
37
|
+
URI.open(url, merged_options) do |file|
|
|
38
|
+
File.binwrite(save_path, file.read)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# 验证文件已下载
|
|
42
|
+
if File.exist?(save_path) && File.size(save_path) > 0
|
|
43
|
+
return true
|
|
44
|
+
else
|
|
45
|
+
raise "下载的文件为空或不存在"
|
|
46
|
+
end
|
|
47
|
+
rescue => e
|
|
48
|
+
last_error = e
|
|
49
|
+
if attempt < max_retries
|
|
50
|
+
Funlog.instance.fancyinfo_error("下载失败 (第#{attempt}次): #{e.message},#{retry_delay}秒后重试...")
|
|
51
|
+
sleep(retry_delay)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# 所有重试都失败
|
|
57
|
+
Funlog.instance.fancyinfo_error("下载失败,已重试#{max_retries}次: #{last_error&.message}")
|
|
58
|
+
false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# 带重试机制的 Icon 下载
|
|
62
|
+
# @param icon_url [String] Icon的下载URL
|
|
63
|
+
# @param save_path [String] 保存路径
|
|
64
|
+
# @param max_retries [Integer] 最大重试次数,默认3次
|
|
65
|
+
# @return [Boolean] 是否下载成功
|
|
66
|
+
def self.download_icon_with_retry(icon_url:, save_path:, max_retries: 3)
|
|
67
|
+
Funlog.instance.fancyinfo_start("正在从 JPS 下载项目 Icon...")
|
|
68
|
+
|
|
69
|
+
success = download_file_with_retry(
|
|
70
|
+
url: icon_url,
|
|
71
|
+
save_path: save_path,
|
|
72
|
+
max_retries: max_retries,
|
|
73
|
+
retry_delay: 2
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if success
|
|
77
|
+
Funlog.instance.fancyinfo_success("Icon 下载成功!")
|
|
78
|
+
else
|
|
79
|
+
Funlog.instance.fancyinfo_error("Icon 下载失败!")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
success
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -98,6 +98,7 @@ module Pindo
|
|
|
98
98
|
when 'ipa' then 'ipa_workflow'
|
|
99
99
|
when 'apk' then 'apk_workflow'
|
|
100
100
|
when 'zip' then 'webgl_workflow'
|
|
101
|
+
when 'app' then 'macos_workflow'
|
|
101
102
|
else
|
|
102
103
|
puts "[JPSConfig] 不支持的 package_type: #{package_type}"
|
|
103
104
|
return result
|
|
@@ -1015,8 +1016,8 @@ module Pindo
|
|
|
1015
1016
|
puts "使用项目配置文件: #{project_cliff_toml}" if ENV['DEBUG']
|
|
1016
1017
|
cliff_config_cmd = "git-cliff -c \"#{project_cliff_toml}\" #{cliff_args} -o -"
|
|
1017
1018
|
else
|
|
1018
|
-
# 策略2: 使用 Pindo
|
|
1019
|
-
pindo_common_dir =
|
|
1019
|
+
# 策略2: 使用 Pindo 默认配置文件(直接从 Pindoconfig 获取目录,避免更新仓库)
|
|
1020
|
+
pindo_common_dir = Pindoconfig.instance.pindo_common_configdir
|
|
1020
1021
|
pindo_cliff_toml = File.join(pindo_common_dir, 'cliff.toml')
|
|
1021
1022
|
if File.exist?(pindo_cliff_toml)
|
|
1022
1023
|
puts "使用 Pindo 默认配置文件: #{pindo_cliff_toml}" if ENV['DEBUG']
|
|
@@ -1038,19 +1039,22 @@ module Pindo
|
|
|
1038
1039
|
end
|
|
1039
1040
|
puts "git-cliff 输出成功" if ENV['DEBUG']
|
|
1040
1041
|
else
|
|
1041
|
-
|
|
1042
|
+
Funlog.warning("git-cliff 执行失败,使用默认描述")
|
|
1042
1043
|
error_msg = stderr && !stderr.empty? ? stderr : stdout
|
|
1043
|
-
puts "
|
|
1044
|
-
|
|
1045
|
-
|
|
1044
|
+
puts "错误信息: #{error_msg}" if ENV['DEBUG']
|
|
1045
|
+
# 使用默认描述而不是抛出异常
|
|
1046
|
+
description = "版本更新"
|
|
1046
1047
|
end
|
|
1047
1048
|
else
|
|
1048
1049
|
# 没有找到任何配置文件
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1050
|
+
Funlog.warning("未找到 cliff.toml 配置文件,使用默认描述")
|
|
1051
|
+
if ENV['DEBUG']
|
|
1052
|
+
puts "请确保:"
|
|
1053
|
+
puts " 1. 项目根目录存在 cliff.toml 文件"
|
|
1054
|
+
puts " 2. 或 Pindo 工具目录存在默认配置文件"
|
|
1055
|
+
end
|
|
1056
|
+
# 使用默认描述而不是抛出异常
|
|
1057
|
+
description = "版本更新"
|
|
1054
1058
|
end
|
|
1055
1059
|
|
|
1056
1060
|
Dir.chdir(temp_dir)
|
|
@@ -1195,6 +1199,7 @@ module Pindo
|
|
|
1195
1199
|
when 'ipa' then 'ipa_workflow'
|
|
1196
1200
|
when 'apk' then 'apk_workflow'
|
|
1197
1201
|
when 'zip' then 'webgl_workflow'
|
|
1202
|
+
when 'app' then 'macos_workflow'
|
|
1198
1203
|
else raise Informative, "不支持的 package_type: #{package_type}"
|
|
1199
1204
|
end
|
|
1200
1205
|
|