pindo 5.11.4 → 5.12.1

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/command/android/autobuild.rb +111 -184
  3. data/lib/pindo/command/android/build.rb +10 -2
  4. data/lib/pindo/command/ios/autobuild.rb +115 -210
  5. data/lib/pindo/command/ios/build.rb +12 -3
  6. data/lib/pindo/command/jps/upload.rb +257 -117
  7. data/lib/pindo/command/unity/autobuild.rb +308 -220
  8. data/lib/pindo/command/unity.rb +0 -3
  9. data/lib/pindo/command/utils/boss.rb +18 -15
  10. data/lib/pindo/command/utils/clearcert.rb +26 -18
  11. data/lib/pindo/command/utils/device.rb +28 -19
  12. data/lib/pindo/command/utils/feishu.rb +11 -4
  13. data/lib/pindo/command/utils/icon.rb +26 -20
  14. data/lib/pindo/command/utils/renewcert.rb +35 -29
  15. data/lib/pindo/command/utils/renewproj.rb +32 -25
  16. data/lib/pindo/command/utils/repoinit.rb +1 -1
  17. data/lib/pindo/command/utils/tag.rb +6 -180
  18. data/lib/pindo/command/utils/tgate.rb +34 -28
  19. data/lib/pindo/command/utils/xcassets.rb +30 -20
  20. data/lib/pindo/command/web/autobuild.rb +148 -128
  21. data/lib/pindo/module/android/android_build_helper.rb +0 -6
  22. data/lib/pindo/module/android/android_config_helper.rb +4 -26
  23. data/lib/pindo/module/build/build_helper.rb +18 -294
  24. data/lib/pindo/module/build/git_repo_helper.rb +519 -0
  25. data/lib/pindo/module/build/icon_downloader.rb +85 -0
  26. data/lib/pindo/module/pgyer/pgyerhelper.rb +16 -11
  27. data/lib/pindo/module/task/model/build/android_dev_build_task.rb +209 -0
  28. data/lib/pindo/module/task/model/build/android_release_build_task.rb +29 -0
  29. data/lib/pindo/module/task/model/build/ios_adhoc_build_task.rb +53 -0
  30. data/lib/pindo/module/task/model/build/ios_dev_build_task.rb +251 -0
  31. data/lib/pindo/module/task/model/build/ios_release_build_task.rb +53 -0
  32. data/lib/pindo/module/task/model/build/web_dev_build_task.rb +43 -0
  33. data/lib/pindo/module/task/model/build_task.rb +125 -301
  34. data/lib/pindo/module/task/model/git_tag_task.rb +80 -0
  35. data/lib/pindo/module/task/model/unity_export_task.rb +53 -41
  36. data/lib/pindo/module/task/model/upload_task.rb +149 -208
  37. data/lib/pindo/module/task/pindo_task.rb +135 -95
  38. data/lib/pindo/module/task/task_manager.rb +202 -352
  39. data/lib/pindo/module/unity/unity_helper.rb +7 -3
  40. data/lib/pindo/module/xcode/xcode_build_config.rb +4 -10
  41. data/lib/pindo/module/xcode/xcode_build_helper.rb +19 -0
  42. data/lib/pindo/version.rb +1 -1
  43. metadata +10 -4
  44. data/lib/pindo/command/unity/apk.rb +0 -185
  45. data/lib/pindo/command/unity/ipa.rb +0 -198
  46. data/lib/pindo/command/unity/web.rb +0 -163
@@ -0,0 +1,519 @@
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
+ Funlog.instance.fancyinfo_error("当前目录不是git仓库,请在git仓库目录下执行此命令")
32
+ return
33
+ end
34
+
35
+ # 获取git仓库根目录
36
+ root_dir = git_root_directory(local_repo_dir: project_dir)
37
+ if root_dir.nil?
38
+ Funlog.instance.fancyinfo_error("无法获取git仓库根目录")
39
+ return
40
+ end
41
+
42
+ # 2. 处理未提交的文件
43
+ process_need_add_files(project_dir: root_dir)
44
+
45
+ # 3. 获取当前分支
46
+ current_branch = git!(%W(-C #{root_dir} rev-parse --abbrev-ref HEAD)).strip
47
+ coding_branch = current_branch
48
+
49
+ # 4. 合并到发布分支
50
+ Funlog.instance.fancyinfo_start("开始合并到#{release_branch}分支")
51
+ merge_to_release_branch(
52
+ project_dir: root_dir,
53
+ release_branch: release_branch,
54
+ coding_branch: coding_branch
55
+ )
56
+
57
+ # 5. 添加版本标签
58
+ add_release_tag(
59
+ project_dir: root_dir,
60
+ increment_mode: mode,
61
+ force_retag: force_retag,
62
+ custom_tag: custom_tag
63
+ )
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
+ unless is_tag_at_head?(git_root_dir: current_git_root_path, tag_name: latest_tag)
196
+ # 检查环境变量
197
+ env_tag_decision = ENV['PINDO_TAG_DECISION']
198
+ if env_tag_decision && !env_tag_decision.empty?
199
+ case env_tag_decision.downcase
200
+ when 'new', 'new_tag', '1'
201
+ puts "\n环境变量指定:新增版本号,打新Tag"
202
+ puts
203
+ tag_action_parms = []
204
+ is_need_add_tag = true
205
+ # 保存到缓存
206
+ context = PindoContext.instance
207
+ decision = {
208
+ tag_action_parms: tag_action_parms,
209
+ is_need_add_tag: is_need_add_tag,
210
+ action: :new_tag,
211
+ description: "新增版本号,打新Tag"
212
+ }
213
+ context.set_selection(PindoContext::SelectionKey::TAG_DECISION, decision)
214
+ return is_need_add_tag, tag_action_parms
215
+ when 'retag', 'recreate', '2'
216
+ puts "\n环境变量指定:将上次的Tag删除重新打Tag"
217
+ puts
218
+ tag_action_parms = ['--retag']
219
+ is_need_add_tag = true
220
+ # 保存到缓存
221
+ context = PindoContext.instance
222
+ decision = {
223
+ tag_action_parms: tag_action_parms,
224
+ is_need_add_tag: is_need_add_tag,
225
+ action: :recreate_tag,
226
+ description: "将上次的Tag删除重新打Tag"
227
+ }
228
+ context.set_selection(PindoContext::SelectionKey::TAG_DECISION, decision)
229
+ return is_need_add_tag, tag_action_parms
230
+ when 'skip', 'no', 'none', '3'
231
+ puts "\n环境变量指定:不需要Tag继续编译"
232
+ puts
233
+ tag_action_parms = nil
234
+ is_need_add_tag = false
235
+ # 保存到缓存
236
+ context = PindoContext.instance
237
+ decision = {
238
+ tag_action_parms: tag_action_parms,
239
+ is_need_add_tag: is_need_add_tag,
240
+ action: :continue_without_tag,
241
+ description: "不需要Tag继续编译且上传"
242
+ }
243
+ context.set_selection(PindoContext::SelectionKey::TAG_DECISION, decision)
244
+ return is_need_add_tag, tag_action_parms
245
+ when 'exit', 'quit', '4'
246
+ Funlog.instance.fancyinfo_error("环境变量指定:终止退出编译!")
247
+ return false, nil
248
+ end
249
+ end
250
+
251
+ if auto_mode
252
+ # 在自动化模式或没有交互式终端时,默认选择新增版本号打新Tag
253
+ puts "检测到当前代码没有打Tag,在自动模式下将自动新增版本号并打新Tag"
254
+ tag_action_parms = []
255
+ is_need_add_tag = true
256
+ else
257
+ # 检查是否已有用户选择
258
+ context = PindoContext.instance
259
+ # 优先从持久化缓存读取,如果没有则从内存临时缓存读取
260
+ cached_decision = context.get_selection(PindoContext::SelectionKey::TAG_DECISION)
261
+
262
+ # 只有当持久化缓存中确实不存在该键时,才从临时缓存读取
263
+ if cached_decision.nil? && !context.has_selection?(PindoContext::SelectionKey::TAG_DECISION)
264
+ # 从 GitRepoHelper 的临时缓存读取
265
+ cached_decision = self.temp_tag_decision
266
+ end
267
+
268
+ if cached_decision && cached_decision.is_a?(Hash)
269
+ # 使用之前的选择
270
+ puts "\n使用之前的选择:#{cached_decision[:description]}"
271
+ tag_action_parms = cached_decision[:tag_action_parms]
272
+ is_need_add_tag = cached_decision[:is_need_add_tag]
273
+
274
+ # 如果是退出选择,则返回
275
+ if cached_decision[:action] == :exit
276
+ Funlog.instance.fancyinfo_error("终止退出编译!")
277
+ return false, nil
278
+ end
279
+ else
280
+ # 第一次询问
281
+ cli = HighLine.new
282
+ selected_action = nil
283
+ selected_description = nil
284
+
285
+ menu_options = {
286
+ "新增版本号,打新Tag" => -> {
287
+ tag_action_parms = []
288
+ selected_action = :new_tag
289
+ selected_description = "新增版本号,打新Tag"
290
+ is_need_add_tag = true
291
+ :new_tag
292
+ },
293
+ "将上次的Tag删除重新打Tag" => -> {
294
+ tag_action_parms = []
295
+ tag_action_parms << "--retag"
296
+ selected_action = :recreate_tag
297
+ selected_description = "将上次的Tag删除重新打Tag"
298
+ is_need_add_tag = true
299
+ :recreate_tag
300
+ },
301
+ "不需要Tag继续编译且上传,手动修改上传备注" => -> {
302
+ puts ""
303
+ tag_action_parms = nil
304
+ selected_action = :continue_without_tag
305
+ selected_description = "不需要Tag继续编译且上传"
306
+ is_need_add_tag = false
307
+ :continue_without_tag
308
+ },
309
+ "终止退出编译" => -> {
310
+ tag_action_parms = nil
311
+ selected_action = :exit
312
+ selected_description = "终止退出编译"
313
+ is_need_add_tag = false
314
+ Funlog.instance.fancyinfo_error("终止退出编译!")
315
+ :exit
316
+ }
317
+ }
318
+
319
+ result = cli.choose do |menu|
320
+ menu.header = "当前代码并没有打Tag,上传的Changelog需要Tag"
321
+ menu.prompt = "请选中打Tag的方式, 请输入选项(1/2/3...):"
322
+ menu_options.each do |option, action|
323
+ menu.choice(option) { action.call }
324
+ end
325
+ end
326
+
327
+ # 如果选择退出,直接返回
328
+ return false, nil if selected_action == :exit
329
+
330
+ # 保存用户选择
331
+ # 只有选择"新增版本号,打新Tag"时才保存到持久化缓存
332
+ if selected_action == :new_tag
333
+ # 保存到持久化缓存(文件)
334
+ context.set_selection(PindoContext::SelectionKey::TAG_DECISION, {
335
+ action: selected_action,
336
+ description: selected_description,
337
+ tag_action_parms: tag_action_parms,
338
+ is_need_add_tag: is_need_add_tag
339
+ })
340
+ # 清除临时缓存
341
+ self.temp_tag_decision = nil
342
+ else
343
+ # 清空持久化缓存
344
+ context.set_selection(PindoContext::SelectionKey::TAG_DECISION, nil)
345
+ # 保存到临时缓存(仅在内存中,不会写入文件)
346
+ self.temp_tag_decision = {
347
+ action: selected_action,
348
+ description: selected_description,
349
+ tag_action_parms: tag_action_parms,
350
+ is_need_add_tag: is_need_add_tag
351
+ }
352
+ end
353
+ end
354
+ end
355
+ end
356
+ end
357
+
358
+ return [is_need_add_tag, tag_action_parms]
359
+ end
360
+
361
+ private
362
+
363
+ # 添加版本标签
364
+ # @param project_dir [String] 项目目录
365
+ # @param increment_mode [String] 版本号增加模式 (major/minor/patch)
366
+ # @param force_retag [Boolean] 是否强制重新打tag
367
+ # @param custom_tag [String] 自定义tag版本号
368
+ def add_release_tag(project_dir:, increment_mode: "minor", force_retag: false, custom_tag: nil)
369
+ raise ArgumentError, "项目目录不能为空" if project_dir.nil?
370
+
371
+ # 如果指定了自定义tag,直接使用
372
+ if custom_tag && !custom_tag.empty?
373
+ Funlog.instance.fancyinfo_start("使用指定的tag版本: #{custom_tag}")
374
+
375
+ # 确保tag有v前缀
376
+ new_tag = custom_tag.start_with?('v') ? custom_tag : "v#{custom_tag}"
377
+
378
+ # 检查tag是否已存在
379
+ existing_tags = git!(%W(-C #{project_dir} tag -l)).split("\n")
380
+ if existing_tags.include?(new_tag)
381
+ if force_retag
382
+ Funlog.instance.fancyinfo_update("tag #{new_tag} 已存在,强制重新打tag")
383
+ git!(%W(-C #{project_dir} tag -d #{new_tag}))
384
+ git!(%W(-C #{project_dir} push origin :refs/tags/#{new_tag}))
385
+ else
386
+ Funlog.instance.fancyinfo_success("tag #{new_tag} 已存在")
387
+ Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
388
+ return
389
+ end
390
+ end
391
+
392
+ # 创建tag并推送
393
+ git!(%W(-C #{project_dir} tag #{new_tag}))
394
+ git!(%W(-C #{project_dir} push origin #{new_tag}))
395
+
396
+ Funlog.instance.fancyinfo_success("创建tag: #{new_tag}")
397
+ Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
398
+ return
399
+ end
400
+
401
+ # 原有的自动递增逻辑
402
+ Funlog.instance.fancyinfo_start("开始创建初tag")
403
+ latest_tag = get_latest_version_tag(project_dir: project_dir)
404
+ if latest_tag.nil?
405
+ new_tag = create_next_version_tag(
406
+ project_dir: project_dir,
407
+ tag_prefix: "v",
408
+ increment_mode: increment_mode,
409
+ force_retag: false
410
+ )
411
+ Funlog.instance.fancyinfo_success("创建初始tag: #{new_tag}")
412
+ Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
413
+ return
414
+ end
415
+
416
+ if is_tag_at_head?(git_root_dir: project_dir, tag_name: latest_tag)
417
+ Funlog.instance.fancyinfo_success("当前commit已有tag: #{latest_tag},无需重新打tag")
418
+ Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
419
+ return
420
+ end
421
+
422
+ Funlog.instance.fancyinfo_success("最近的上次tag是: #{latest_tag} ")
423
+ new_tag = create_next_version_tag(
424
+ project_dir: project_dir,
425
+ tag_prefix: "v",
426
+ increment_mode: increment_mode,
427
+ force_retag: force_retag
428
+ )
429
+
430
+ Funlog.instance.fancyinfo_success("当前仓库的tag: #{new_tag}")
431
+ Funlog.instance.fancyinfo_success("仓库路径: #{project_dir}")
432
+ end
433
+
434
+ # 合并到发布分支
435
+ # @param project_dir [String] 项目目录
436
+ # @param release_branch [String] 发布分支名称
437
+ # @param coding_branch [String] 当前开发分支名称
438
+ def merge_to_release_branch(project_dir:, release_branch:, coding_branch:)
439
+ current_project_dir = project_dir
440
+ Funlog.instance.fancyinfo_start("开始合并到#{release_branch}分支")
441
+ if !coding_branch.eql?(release_branch)
442
+ coding_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{coding_branch})).strip
443
+ release_branch_commit_id = nil
444
+
445
+ if remote_branch_exists?(local_repo_dir: current_project_dir, branch: release_branch)
446
+ Funlog.instance.fancyinfo_update("存在#{release_branch}远程分支")
447
+ if local_branch_exists?(local_repo_dir: current_project_dir, branch: release_branch)
448
+ Funlog.instance.fancyinfo_update("存在#{release_branch}本地分支")
449
+ git!(%W(-C #{current_project_dir} checkout #{release_branch}))
450
+ else
451
+ Funlog.instance.fancyinfo_update("不存在#{release_branch}本地分支")
452
+ git!(%W(-C #{current_project_dir} checkout -b #{release_branch} origin/#{release_branch}))
453
+ end
454
+
455
+ git!(%W(-C #{current_project_dir} branch --set-upstream-to=origin/#{release_branch} #{release_branch}))
456
+ git!(%W(-C #{current_project_dir} fetch origin #{release_branch}))
457
+ git!(%W(-C #{current_project_dir} merge origin/#{release_branch}))
458
+
459
+ # 执行合并操作,捕获输出以便后续检查冲突
460
+ stdout, exit_status = Executable.capture_command('git', %W(-C #{current_project_dir} merge #{coding_branch}), :capture => :out)
461
+
462
+ # 检查是否有冲突(git merge 在有冲突时返回非0状态)
463
+ conflict_filelist = git!(%W(-C #{current_project_dir} diff --name-only --diff-filter=U --relative))
464
+ if !conflict_filelist.nil? && conflict_filelist.size > 0
465
+ puts "合并代码冲突, 冲突文件如下:"
466
+ raise Informative, "请手动处理冲突的文件!!!"
467
+ else
468
+ git!(%W(-C #{current_project_dir} push))
469
+ Funlog.instance.fancyinfo_success("代码已经合并到#{release_branch}分支")
470
+ # 获取 release_branch 的 commit ID(处理空分支情况)
471
+ begin
472
+ release_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{release_branch})).strip
473
+ rescue => e
474
+ # 分支可能存在但没有提交(空分支),此时使用 coding_branch 的 commit
475
+ Funlog.instance.fancyinfo_update("#{release_branch}分支为空或获取commit失败,将使用当前分支commit")
476
+ release_branch_commit_id = coding_branch_commit_id
477
+ end
478
+ end
479
+
480
+ else
481
+ if local_branch_exists?(local_repo_dir: current_project_dir, branch: release_branch)
482
+ Funlog.instance.fancyinfo_update("不存在#{release_branch}远程分支")
483
+ Funlog.instance.fancyinfo_update("存在#{release_branch}本地分支")
484
+ git!(%W(-C #{current_project_dir} checkout #{release_branch}))
485
+ git!(%W(-C #{current_project_dir} checkout -b #{release_branch}_temp))
486
+ git!(%W(-C #{current_project_dir} checkout #{coding_branch}))
487
+ git!(%W(-C #{current_project_dir} branch -D #{release_branch}))
488
+ else
489
+ Funlog.instance.fancyinfo_update("不存在#{release_branch}远程分支")
490
+ Funlog.instance.fancyinfo_update("不存在#{release_branch}本地分支")
491
+ end
492
+
493
+ git!(%W(-C #{current_project_dir} checkout -b #{release_branch}))
494
+ git!(%W(-C #{current_project_dir} push origin #{release_branch}))
495
+ git!(%W(-C #{current_project_dir} branch --set-upstream-to=origin/#{release_branch} #{release_branch}))
496
+
497
+ Funlog.instance.fancyinfo_success("代码已经合并到#{release_branch}分支")
498
+ # 获取 release_branch 的 commit ID(处理空分支情况)
499
+ begin
500
+ release_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{release_branch})).strip
501
+ rescue => e
502
+ # 新创建的分支,commit ID 应该与 coding_branch 相同
503
+ release_branch_commit_id = coding_branch_commit_id
504
+ end
505
+ end
506
+
507
+ git!(%W(-C #{current_project_dir} checkout #{coding_branch}))
508
+ if release_branch_commit_id && !release_branch_commit_id.eql?(coding_branch_commit_id)
509
+ git!(%W(-C #{current_project_dir} merge #{release_branch}))
510
+ Funlog.instance.fancyinfo_success("已将#{release_branch}合并到#{coding_branch}")
511
+ end
512
+ git!(%W(-C #{current_project_dir} push origin #{coding_branch}))
513
+ Funlog.instance.fancyinfo_success("已推送#{coding_branch}分支到远程")
514
+ else
515
+ Funlog.instance.fancyinfo_success("代码处于#{coding_branch}分支,无需合并")
516
+ end
517
+ end
518
+ end
519
+ 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 默认配置文件(使用与 check_and_install_cliff 相同的方法)
1019
- pindo_common_dir = clone_pindo_common_config_repo(force_delete:false)
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
- puts "\n\e[31m错误: git-cliff 执行失败\e[0m"
1042
+ Funlog.warning("git-cliff 执行失败,使用默认描述")
1042
1043
  error_msg = stderr && !stderr.empty? ? stderr : stdout
1043
- puts "\e[31m错误信息: #{error_msg}\e[0m"
1044
- puts "\e[33m请检查 git-cliff 配置或联系管理员\e[0m"
1045
- raise Informative, "git-cliff 执行失败,无法生成版本描述"
1044
+ puts "错误信息: #{error_msg}" if ENV['DEBUG']
1045
+ # 使用默认描述而不是抛出异常
1046
+ description = "版本更新"
1046
1047
  end
1047
1048
  else
1048
1049
  # 没有找到任何配置文件
1049
- puts "\n\e[31m错误: 未找到 cliff.toml 配置文件\e[0m"
1050
- puts "\e[33m请确保:\e[0m"
1051
- puts "\e[36m 1. 项目根目录存在 cliff.toml 文件\e[0m"
1052
- puts "\e[36m 2. Pindo 工具目录存在默认配置文件\e[0m"
1053
- raise Informative, "缺少 cliff.toml 配置文件,无法生成版本描述"
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