pindo 5.13.11 → 5.13.13

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/funlog.rb +62 -5
  3. data/lib/pindo/base/git_handler.rb +83 -22
  4. data/lib/pindo/base/output_sink.rb +69 -0
  5. data/lib/pindo/command/android/autobuild.rb +57 -8
  6. data/lib/pindo/command/appstore/autobuild.rb +10 -1
  7. data/lib/pindo/command/ios/autobuild.rb +59 -7
  8. data/lib/pindo/command/jps/media.rb +185 -58
  9. data/lib/pindo/command/jps/upload.rb +14 -9
  10. data/lib/pindo/command/unity/autobuild.rb +64 -10
  11. data/lib/pindo/command/unity/packpush.rb +27 -3
  12. data/lib/pindo/command/utils/tag.rb +9 -1
  13. data/lib/pindo/command/web/autobuild.rb +59 -10
  14. data/lib/pindo/module/android/android_build_helper.rb +6 -7
  15. data/lib/pindo/module/build/git_repo_helper.rb +29 -25
  16. data/lib/pindo/module/pgyer/pgyerhelper.rb +174 -77
  17. data/lib/pindo/module/task/core/concurrent_execution_strategy.rb +237 -0
  18. data/lib/pindo/module/task/core/dependency_checker.rb +123 -0
  19. data/lib/pindo/module/task/core/execution_strategy.rb +61 -0
  20. data/lib/pindo/module/task/core/resource_lock_manager.rb +190 -0
  21. data/lib/pindo/module/task/core/serial_execution_strategy.rb +60 -0
  22. data/lib/pindo/module/task/core/task_executor.rb +131 -0
  23. data/lib/pindo/module/task/core/task_queue.rb +221 -0
  24. data/lib/pindo/module/task/model/build/android_build_dev_task.rb +1 -1
  25. data/lib/pindo/module/task/model/build/android_build_task.rb +6 -2
  26. data/lib/pindo/module/task/model/build/ios_build_dev_task.rb +2 -3
  27. data/lib/pindo/module/task/model/build/ios_build_task.rb +6 -0
  28. data/lib/pindo/module/task/model/build_task.rb +22 -0
  29. data/lib/pindo/module/task/model/git/git_commit_task.rb +11 -2
  30. data/lib/pindo/module/task/model/git_task.rb +6 -0
  31. data/lib/pindo/module/task/model/jps/jps_message_task.rb +9 -11
  32. data/lib/pindo/module/task/model/jps/jps_upload_media_task.rb +264 -64
  33. data/lib/pindo/module/task/model/jps_task.rb +0 -1
  34. data/lib/pindo/module/task/model/unity_task.rb +38 -2
  35. data/lib/pindo/module/task/output/multi_line_output_manager.rb +380 -0
  36. data/lib/pindo/module/task/output/multi_line_task_display.rb +185 -0
  37. data/lib/pindo/module/task/output/stdout_redirector.rb +95 -0
  38. data/lib/pindo/module/task/pindo_task.rb +133 -9
  39. data/lib/pindo/module/task/task_manager.rb +98 -268
  40. data/lib/pindo/module/task/task_reporter.rb +135 -0
  41. data/lib/pindo/module/task/task_resources/resource_instance.rb +90 -0
  42. data/lib/pindo/module/task/task_resources/resource_registry.rb +105 -0
  43. data/lib/pindo/module/task/task_resources/resource_type.rb +59 -0
  44. data/lib/pindo/module/task/task_resources/types/directory_based_resource.rb +63 -0
  45. data/lib/pindo/module/task/task_resources/types/global_exclusive_resource.rb +33 -0
  46. data/lib/pindo/module/task/task_resources/types/global_shared_resource.rb +34 -0
  47. data/lib/pindo/module/xcode/xcode_build_helper.rb +26 -8
  48. data/lib/pindo/options/groups/jps_options.rb +10 -0
  49. data/lib/pindo/options/groups/task_options.rb +39 -0
  50. data/lib/pindo/version.rb +3 -2
  51. metadata +20 -1
@@ -13,6 +13,7 @@ require 'pindo/module/task/model/unity/unity_yoo_asset_task'
13
13
  require 'pindo/module/task/model/unity/unity_export_task'
14
14
  require 'pindo/module/task/model/build_task'
15
15
  require 'pindo/module/task/model/jps/jps_upload_task'
16
+ require 'pindo/module/task/model/jps/jps_upload_media_task'
16
17
  require 'pindo/module/task/model/jps/jps_message_task'
17
18
  require 'pindo/options/options'
18
19
 
@@ -33,15 +34,17 @@ module Pindo
33
34
  # 命令的详细说明,包含用法示例
34
35
  self.description = <<-DESC
35
36
  编译WebGL包并支持上传到测试平台。
36
-
37
+
37
38
  支持功能:
38
39
 
39
40
  * 编译Debug包
40
41
 
41
- * 上传到测试平台
42
+ * 上传到测试平台
42
43
 
43
44
  * 发送测试通知
44
45
 
46
+ * 支持并发任务执行(使用 --multi 参数)
47
+
45
48
  使用示例:
46
49
 
47
50
  $ pindo web autobuild # 编译Debug包
@@ -50,7 +53,13 @@ module Pindo
50
53
 
51
54
  $ pindo web autobuild --proj=myapp # 指定项目名称
52
55
 
53
- $ pindo web autobuild --run # 编译完成后再本地打开webgl包
56
+ $ pindo web autobuild --media # 编译、上传并上传媒体附件
57
+
58
+ $ pindo web autobuild --run # 编译完成后再本地打开webgl包
59
+
60
+ $ pindo web autobuild --multi # 使用并发模式执行(速度更快)
61
+
62
+ $ pindo web autobuild --multi --upload # 并发执行并上传
54
63
  DESC
55
64
 
56
65
  # 命令的参数列表
@@ -61,9 +70,10 @@ module Pindo
61
70
  # 定义此命令使用的参数项
62
71
  def self.option_items
63
72
  @option_items ||= Pindo::Options::OptionGroup.merge(
64
- Pindo::Options::JPSOptions.select(:proj, :upload, :send),
73
+ Pindo::Options::JPSOptions.select(:proj, :upload, :send, :media),
65
74
  Pindo::Options::UnityOptions.select(:skiplib, :skipyoo),
66
75
  Pindo::Options::UnityOptions.select_with_defaults(skipconfig: true),
76
+ Pindo::Options::TaskOptions.select(:multi),
67
77
  Pindo::Options::GitOptions.all
68
78
  )
69
79
  end
@@ -83,19 +93,23 @@ module Pindo
83
93
  @args_adhoc_flag = argv.flag?('adhoc', false)
84
94
  @args_upload_flag = @options[:upload] || false
85
95
  @args_send_flag = @options[:send] || false
96
+ @args_media_flag = @options[:media] || false
86
97
  @args_proj_name = @options[:proj]
87
98
  @args_bundle_id = argv.option('bundleid')
88
99
  @args_run_flag = argv.flag?('run', false)
89
100
  @args_skip_lib = @options[:skiplib] || false
90
101
  @args_skip_yoo = @options[:skipyoo] || false
91
102
 
103
+ # Task 参数
104
+ @args_multi_flag = @options[:multi] || false
105
+
92
106
  # Git 参数
93
107
  @args_release_branch = @options[:release_branch] || 'master'
94
108
  @args_ver_inc = Pindo::Options::GitOptions.parse_version_increase_type(@options[:ver_inc] || 'mini')
95
109
  @args_tag_type = Pindo::Options::GitOptions.parse_create_tag_type(@options[:tag_type] || 'new')
96
110
  @args_tag_pre = @options[:tag_pre] || 'v'
97
111
 
98
- if @args_send_flag
112
+ if @args_send_flag || @args_media_flag
99
113
  @args_upload_flag = true
100
114
  end
101
115
 
@@ -124,7 +138,13 @@ module Pindo
124
138
  task_manager = Pindo::TaskSystem::TaskManager.instance
125
139
  task_manager.clear_all
126
140
  tasks.each { |task| task_manager.add_task(task) }
127
- task_manager.start
141
+
142
+ # 执行任务(根据 --multi 参数决定模式)
143
+ if @args_multi_flag
144
+ task_manager.start(mode: :concurrent, max_workers: 3)
145
+ else
146
+ task_manager.start
147
+ end
128
148
 
129
149
  system "open #{pindo_project_dir}"
130
150
 
@@ -204,12 +224,20 @@ module Pindo
204
224
 
205
225
  # 1. Git 提交任务(如果需要上传)
206
226
  if @args_upload_flag
227
+ # 提前询问用户如何处理未提交的文件
228
+ process_type = Pindo::GitHandler.get_uncommitted_files_process_type(
229
+ project_dir: config[:project_path],
230
+ interactive: true
231
+ )
232
+
207
233
  git_commit_task = Pindo::TaskSystem::GitCommitTask.new(
208
234
  config[:project_path],
209
235
  release_branch: @args_release_branch,
210
236
  ver_inc: @args_ver_inc,
211
237
  tag_type: @args_tag_type,
212
- tag_pre: @args_tag_pre
238
+ tag_pre: @args_tag_pre,
239
+ process_type: process_type,
240
+ commit_message: "feat: web autobuild 构建前提交"
213
241
  )
214
242
  tasks << git_commit_task
215
243
  last_task = git_commit_task
@@ -300,19 +328,40 @@ module Pindo
300
328
  upload_task.dependencies << build_task.id
301
329
  tasks << upload_task
302
330
 
303
- # 7.2 创建消息发送任务(依赖上传任务)
331
+ # 7.2 创建消息发送任务(只依赖上传任务)
304
332
  # app_version_info 将从 upload_task 的数据参数中获取
305
333
  message_task = Pindo::TaskSystem::JPSMessageTask.new(
306
334
  nil, # app_version_info 为 nil,从依赖任务获取
307
335
  app_info_obj: config[:app_info_obj],
308
336
  project_name: @args_proj_name,
309
337
  send_message_type: @args_send_flag ? 'group' : 'self',
310
- data_dependencies: [upload_task.id] # 从 upload_task 获取数据
338
+ dependencies: [upload_task.id] # 从 upload_task 获取数据
311
339
  )
312
- message_task.dependencies << upload_task.id # 执行顺序依赖
313
340
  tasks << message_task
314
341
  end
315
342
 
343
+ # 8. 创建媒体附件上传任务(如果需要,只依赖 Git 提交任务)
344
+ if @args_media_flag
345
+ # 获取 Git 管理类型的工作流(不同于 HTML 上传的工作流)
346
+ git_app_info_obj, git_workflow_info = PgyerHelper.share_instace.prepare_upload(
347
+ working_directory: config[:project_path],
348
+ proj_name: @args_proj_name,
349
+ package_type: "", # package_type 在 manage_type=git 时会被忽略
350
+ manage_type: "git"
351
+ )
352
+
353
+ media_upload_task = Pindo::TaskSystem::JPSUploadMediaTask.new(
354
+ [], # 空数组,自动从 JPSMedia/ 目录查找
355
+ config[:project_path], # upload_path
356
+ app_info_obj: git_app_info_obj,
357
+ workflow_info: git_workflow_info,
358
+ project_name: @args_proj_name
359
+ )
360
+ # 只依赖 Git 提交任务
361
+ media_upload_task.dependencies << git_commit_task.id
362
+ tasks << media_upload_task
363
+ end
364
+
316
365
  tasks
317
366
  else
318
367
  raise Informative, "Web 编译只支持 Unity 工程"
@@ -239,16 +239,15 @@ module Pindo
239
239
  end
240
240
 
241
241
  def build_aab(project_path, debug)
242
- Dir.chdir(project_path) do
243
- system("./gradlew bundle#{debug ? 'Debug' : 'Release'}")
244
- end
242
+ # 使用子 Shell 切换目录执行,避免影响主进程当前目录 (Thread Safe)
243
+ cmd = "cd \"#{project_path}\" && ./gradlew bundle#{debug ? 'Debug' : 'Release'}"
244
+ system(cmd)
245
245
  end
246
246
 
247
247
  def build_so_library(project_path)
248
- # 编译so库
249
- Dir.chdir(project_path) do
250
- system("./gradlew unityLibrary:BuildIl2CppTask")
251
- end
248
+ # 编译so库 (Thread Safe)
249
+ cmd = "cd \"#{project_path}\" && ./gradlew unityLibrary:BuildIl2CppTask"
250
+ system(cmd)
252
251
  end
253
252
 
254
253
  def copy_so_files(source_path, target_path)
@@ -58,7 +58,7 @@ module Pindo
58
58
  if Pindo::GitHandler.is_git_directory?(local_repo_dir: project_path)
59
59
  current_git_root_path = Pindo::GitHandler.git_root_directory(local_repo_dir: project_path)
60
60
  Dir.chdir(current_git_root_path)
61
- pindo_common_dir = clone_pindo_common_config_repo(force_delete:false)
61
+ pindo_common_dir = Pindoconfig.instance.pindo_common_configdir
62
62
  if File.exist?(File.join(pindo_common_dir, 'cliff.toml'))
63
63
  FileUtils.cp_r(File.join(pindo_common_dir, 'cliff.toml'), File.join(current_git_root_path, 'cliff.toml'))
64
64
  end
@@ -104,30 +104,34 @@ module Pindo
104
104
  gitignore_path = File.join(git_root_dir, '.gitignore')
105
105
  file_modified = false
106
106
 
107
- # 定义要添加的gitignore规则数组
108
- ignore_rules = [
109
- 'Temp',
110
- 'Logs',
111
- 'build_ios.log',
112
- 'feishu.json',
113
- 'CHANGELOG.md',
114
- 'GoodPlatform/iOS/*',
115
- 'GoodPlatform/Android/*',
116
- 'GoodPlatform/BaseiOS/Unity/*',
117
- 'GoodPlatform/BaseiOS/Pods/',
118
- 'GoodPlatform/BaseiOS/build',
119
- 'GoodPlatform/BaseiOS/config.json',
120
- 'GoodPlatform/BaseiOS/Podfile.lock',
121
- 'GoodPlatform/BaseAndroid/Unity/*',
122
- 'GoodPlatform/BaseAndroid/build',
123
- 'GoodPlatform/WebGL',
124
- 'config.json',
125
- 'Assets/Packages',
126
- 'Assets/WebGLTemplates.meta',
127
- 'Assets/WebGLTemplates/',
128
- 'JPSMedia',
129
- 'Packages/packages-lock.json'
130
- ]
107
+ # 从 pindo_common_config 读取 gitignore 规则
108
+ ignore_rules = []
109
+ begin
110
+ pindo_common_dir = Pindoconfig.instance.pindo_common_configdir
111
+ template_file = File.join(pindo_common_dir, 'gitignore_template.txt')
112
+
113
+ if File.exist?(template_file)
114
+ # 读取模板文件并解析每一行
115
+ File.readlines(template_file).each do |line|
116
+ # 去掉前后空白
117
+ rule = line.strip
118
+ # 去掉末尾的逗号
119
+ rule = rule.chomp(',')
120
+ # 去掉开头和结尾的单引号
121
+ rule = rule.gsub(/^'/, '').gsub(/'$/, '')
122
+ # 再次去掉空白
123
+ rule = rule.strip
124
+ # 跳过空行
125
+ ignore_rules << rule unless rule.empty?
126
+ end
127
+ else
128
+ Funlog.instance.fancyinfo_warning("未找到 gitignore_template.txt,跳过添加规则")
129
+ return false
130
+ end
131
+ rescue => e
132
+ Funlog.instance.fancyinfo_error("读取 gitignore 模板失败: #{e.message}")
133
+ return false
134
+ end
131
135
 
132
136
  # 读取现有的gitignore内容
133
137
  existing_lines = []
@@ -55,7 +55,7 @@ module Pindo
55
55
  # - project_name [String] 项目名称
56
56
  # - project_id [String] 项目ID
57
57
  # - workflow_info [Hash] 工作流信息(如果有效)
58
- def try_load_jps_build_config(working_directory:, package_type:)
58
+ def try_load_jps_build_config(working_directory:, package_type:, manage_type: "")
59
59
  result = {
60
60
  valid: false,
61
61
  project_name: nil,
@@ -89,15 +89,24 @@ module Pindo
89
89
  return result
90
90
  end
91
91
 
92
- # 5. 确定 workflow_key
93
- workflow_key = case package_type
94
- when 'ipa' then 'ipa_workflow'
95
- when 'apk' then 'apk_workflow'
96
- when 'zip' then 'webgl_workflow'
97
- when 'app' then 'macos_workflow'
98
- else
99
- puts "[JPSConfig] 不支持的 package_type: #{package_type}"
100
- return result
92
+ # 5. 根据 manage_type 决定 workflow_key
93
+ workflow_key = nil
94
+
95
+ if manage_type == "git"
96
+ # manage_type git 时,直接使用 git_workflow
97
+ workflow_key = 'git_workflow'
98
+ puts "[JPSConfig] 使用 git_workflow 配置" if ENV['DEBUG']
99
+ else
100
+ # 按 package_type 查找
101
+ workflow_key = case package_type
102
+ when 'ipa' then 'ipa_workflow'
103
+ when 'apk' then 'apk_workflow'
104
+ when 'zip' then 'webgl_workflow'
105
+ when 'app' then 'macos_workflow'
106
+ else
107
+ puts "[JPSConfig] 不支持的 package_type: #{package_type}"
108
+ return result
109
+ end
101
110
  end
102
111
 
103
112
  # 6. 验证工作流配置
@@ -118,7 +127,7 @@ module Pindo
118
127
  manage_type: workflow['manage_type'] || ""
119
128
  }
120
129
 
121
- puts "[JPSConfig] 配置验证通过" if ENV['DEBUG']
130
+ puts "[JPSConfig] 配置验证通过 (#{workflow_key})" if ENV['DEBUG']
122
131
  return result
123
132
  end
124
133
 
@@ -127,8 +136,9 @@ module Pindo
127
136
  # @param project_id [String] 项目ID
128
137
  # @param package_type [String] 包类型
129
138
  # @param working_directory [String] 工作目录
139
+ # @param manage_type [String] 管理类型(默认为空,"git" 时筛选 git 工作流)
130
140
  # @return [Hash] 选择的工作流信息
131
- def select_workflow_for_project(project_id:, package_type:, working_directory:)
141
+ def select_workflow_for_project(project_id:, package_type:, working_directory:, manage_type: "")
132
142
  # 1. 从 JPS API 获取可用工作流列表
133
143
  Funlog.instance.fancyinfo_start("正在获取可用工作流...")
134
144
 
@@ -146,37 +156,49 @@ module Pindo
146
156
 
147
157
  Funlog.instance.fancyinfo_success("获取工作流列表成功,共 #{workflows.size} 个工作流")
148
158
 
149
- # 2. 根据 package_type 过滤工作流(如果 API 返回的数据中有 packageType 字段)
150
- filtered_workflows = workflows.select do |w|
151
- # 如果工作流有 packageType 字段,进行过滤
152
- if w['packageType']
153
- case package_type
154
- when 'ipa'
155
- w['packageType'] == 'ipa'
156
- when 'apk'
157
- w['packageType'] == 'apk'
158
- when 'zip'
159
- w['packageType'] == 'zip'
159
+ # 2. 根据 manage_type package_type 过滤工作流
160
+ if manage_type == "git"
161
+ # manage_type git 时,只筛选 manage_type == "git" 的工作流,不看 package_type
162
+ # 严格筛选,不包括 manage_type 为空或其他类型的工作流
163
+ filtered_workflows = workflows.select do |w|
164
+ (w['manageType'] == 'git') || (w['manage_type'] == 'git')
165
+ end
166
+ type_desc = 'Git 管理类型'
167
+ # manage_type == "git" 时严格使用筛选结果,不降级
168
+ display_workflows = filtered_workflows
169
+ else
170
+ # 按 package_type 过滤工作流
171
+ filtered_workflows = workflows.select do |w|
172
+ # 如果工作流有 packageType 字段,进行过滤
173
+ if w['packageType']
174
+ case package_type
175
+ when 'ipa'
176
+ w['packageType'] == 'ipa'
177
+ when 'apk'
178
+ w['packageType'] == 'apk'
179
+ when 'zip'
180
+ w['packageType'] == 'zip'
181
+ else
182
+ true
183
+ end
160
184
  else
185
+ # 如果没有 packageType 字段,显示所有工作流
161
186
  true
162
187
  end
163
- else
164
- # 如果没有 packageType 字段,显示所有工作流
165
- true
166
188
  end
167
- end
168
189
 
169
- # 如果过滤后没有结果,使用所有工作流
170
- display_workflows = filtered_workflows.empty? ? workflows : filtered_workflows
190
+ type_desc = case package_type
191
+ when 'ipa' then 'iOS IPA'
192
+ when 'apk' then 'Android APK'
193
+ when 'zip' then 'WebGL'
194
+ else package_type
195
+ end
171
196
 
172
- # 3. 根据匹配数量决定选择方式
173
- type_desc = case package_type
174
- when 'ipa' then 'iOS IPA'
175
- when 'apk' then 'Android APK'
176
- when 'zip' then 'WebGL'
177
- else package_type
197
+ # git 模式下,如果过滤后没有结果,使用所有工作流
198
+ display_workflows = filtered_workflows.empty? ? workflows : filtered_workflows
178
199
  end
179
200
 
201
+ # 3. 根据匹配数量决定选择方式
180
202
  workflow = nil
181
203
 
182
204
  if display_workflows.empty?
@@ -378,7 +400,7 @@ module Pindo
378
400
  return app_info_obj, workflow_info
379
401
  end
380
402
 
381
- def prepare_upload(working_directory:nil, proj_name:nil, package_type:nil)
403
+ def prepare_upload(working_directory:nil, proj_name:nil, package_type:nil, manage_type: "")
382
404
  upload_proj_name = proj_name
383
405
  if upload_proj_name.nil? || upload_proj_name.empty?
384
406
  upload_proj_name = @proj_name
@@ -396,7 +418,8 @@ module Pindo
396
418
  if package_type
397
419
  config_result = try_load_jps_build_config(
398
420
  working_directory: working_directory,
399
- package_type: package_type
421
+ package_type: package_type,
422
+ manage_type: manage_type
400
423
  )
401
424
 
402
425
  if config_result[:valid]
@@ -444,14 +467,16 @@ module Pindo
444
467
  workflow_info = select_workflow_for_project(
445
468
  project_id: app_info_obj["id"],
446
469
  package_type: package_type,
447
- working_directory: working_directory
470
+ working_directory: working_directory,
471
+ manage_type: manage_type
448
472
  )
449
473
 
450
474
  save_jps_build_config(
451
475
  working_directory: working_directory,
452
476
  app_info_obj: app_info_obj,
453
477
  workflow_info: workflow_info,
454
- package_type: package_type
478
+ package_type: package_type,
479
+ manage_type: manage_type
455
480
  )
456
481
 
457
482
  @proj_name = upload_proj_name
@@ -568,14 +593,16 @@ module Pindo
568
593
  workflow_info = select_workflow_for_project(
569
594
  project_id: app_info_obj["id"],
570
595
  package_type: package_type,
571
- working_directory: working_directory
596
+ working_directory: working_directory,
597
+ manage_type: manage_type
572
598
  )
573
599
 
574
600
  save_jps_build_config(
575
601
  working_directory: working_directory,
576
602
  app_info_obj: app_info_obj,
577
603
  workflow_info: workflow_info,
578
- package_type: package_type
604
+ package_type: package_type,
605
+ manage_type: manage_type
579
606
  )
580
607
 
581
608
  @proj_name = upload_proj_name
@@ -821,70 +848,120 @@ module Pindo
821
848
  end
822
849
 
823
850
  # 2. 根据 git_commit_id 查找对应的 commit_log 记录
824
- Funlog.instance.fancyinfo_start("正在根据 git commit id 查找 JPS 提交记录...")
851
+ Funlog.instance.fancyinfo_start("查找 JPS 提交记录...")
825
852
  commit_log = find_commit_log_by_git_commit_id(git_commit_id, workflow_id)
826
853
 
827
854
  if commit_log.nil?
828
- Funlog.instance.fancyinfo_error("未找到 git commit id: #{git_commit_id} 对应的 JPS 提交记录")
829
- Funlog.instance.warning("请确保该 commit 已经通过 JPS 发送过消息通知")
855
+ Funlog.instance.fancyinfo_error("未找到对应的 JPS 提交记录")
856
+ Funlog.instance.warning("请确保该 commit 已通过 JPS 发送过消息")
830
857
  return result
831
858
  end
832
859
 
833
860
  commit_log_id = commit_log["id"]
834
861
  result[:commit_log_id] = commit_log_id
835
862
 
836
- Funlog.instance.fancyinfo_success("找到 JPS 提交记录 ##{commit_log_id}")
837
- puts " 项目: #{commit_log["projectName"]}"
838
- puts " 工作流: #{commit_log["tabName"]}"
839
- puts " 分支: #{commit_log["branch"]}"
840
- puts
863
+ Funlog.instance.fancyinfo_success("找到提交记录 ##{commit_log_id}")
864
+ puts " #{commit_log["projectName"]} / #{commit_log["tabName"]} / #{commit_log["branch"]}"
841
865
 
842
866
  # 3. 获取已存在的 fileUrls
843
867
  if commit_log["fileUrls"] && commit_log["fileUrls"].any?
844
868
  result[:existing_urls] = commit_log["fileUrls"]
845
- puts "已有附件: #{result[:existing_urls].size} 个"
869
+ puts " 已有附件: #{result[:existing_urls].size} 个"
846
870
  end
871
+ puts ""
872
+
873
+ # 4. 显示待上传的文件列表
874
+ puts " 📤 待上传文件(共 #{file_paths.size} 个)"
875
+ file_paths.each_with_index do |file_path, index|
876
+ if File.exist?(file_path)
877
+ size_bytes = File.size(file_path)
878
+ size_str = format_file_size(size_bytes)
879
+ file_name = File.basename(file_path)
880
+ puts " #{index + 1}. #{file_name} (#{size_str})"
881
+ end
882
+ end
883
+ puts ""
884
+
885
+ # 5. 使用 UploadMediaClient 并发上传文件
886
+ Funlog.instance.fancyinfo_start("正在上传...")
847
887
 
848
- # 4. 使用 UploadMediaClient 并发上传文件
849
888
  media_client = JPSClient::UploadMediaClient.new(@pgyer_client)
850
- upload_result = media_client.upload_files(file_paths: file_paths)
851
889
 
852
- # 5. 提取上传结果
890
+ # 在非调试模式下,临时重定向 JPSClient 的输出
891
+ if ENV['PINDO_DEBUG']
892
+ upload_result = media_client.upload_files(file_paths: file_paths)
893
+ else
894
+ # 保存原始的 stdout
895
+ original_stdout = $stdout.clone
896
+ # 临时重定向到 /dev/null
897
+ $stdout.reopen(File.new('/dev/null', 'w'))
898
+ begin
899
+ upload_result = media_client.upload_files(file_paths: file_paths)
900
+ ensure
901
+ # 恢复原始的 stdout
902
+ $stdout.reopen(original_stdout)
903
+ end
904
+ end
905
+
906
+ # 6. 提取上传结果
853
907
  result[:success_urls] = upload_result["success_urls"]
854
908
  result[:failed_files] = upload_result["failed_files"]
855
909
 
856
- # 6. 合并 URL 列表
910
+ # 显示上传结果
911
+ if result[:failed_files].any?
912
+ Funlog.instance.fancyinfo_error("上传完成:成功 #{result[:success_urls].size} 个,失败 #{result[:failed_files].size} 个")
913
+ else
914
+ Funlog.instance.fancyinfo_success("上传完成:成功 #{result[:success_urls].size} 个")
915
+ end
916
+
917
+ # 7. 合并 URL 列表
857
918
  result[:all_urls] = result[:existing_urls] + result[:success_urls]
858
919
 
859
- # 7. 更新 commit_log
920
+ # 8. 更新 commit_log
860
921
  if result[:success_urls].any?
861
- Funlog.instance.fancyinfo_start("正在更新提交记录附件...")
922
+ Funlog.instance.fancyinfo_start("更新提交记录...")
862
923
  begin
863
924
  update_result = @pgyer_client.update_commit_log(
864
925
  id: commit_log_id,
865
926
  params: { fileUrls: result[:all_urls] }
866
927
  )
867
928
 
868
- if update_result && (update_result.dig("meta", "code") == 0 || update_result.dig("meta", "code") == 200)
929
+ # 兼容两种响应格式:
930
+ # 1. 新格式:{"code": 0, "data": ..., "msg": ...}
931
+ # 2. 旧格式:{"meta": {"code": 0}, ...}
932
+ response_code = update_result&.dig("code") || update_result&.dig("meta", "code")
933
+
934
+ if update_result && (response_code == 0 || response_code == 200)
869
935
  result[:update_success] = true
870
- Funlog.instance.fancyinfo_success("提交记录附件更新成功!共 #{result[:all_urls].size} 个附件")
936
+ Funlog.instance.fancyinfo_success("附件已更新(共 #{result[:all_urls].size} 个)")
871
937
  else
872
- error_msg = update_result&.dig("meta", "message") || "未知错误"
873
- Funlog.instance.fancyinfo_error("更新提交记录失败: #{error_msg}")
938
+ # 提取详细错误信息
939
+ error_code = update_result&.dig("code") || update_result&.dig("meta", "code")
940
+ error_msg = update_result&.dig("msg") || update_result&.dig("meta", "message") || update_result&.dig("message")
941
+
942
+ if ENV['PINDO_DEBUG']
943
+ puts "[PINDO_DEBUG] update_commit_log 返回结果: #{update_result.inspect}"
944
+ puts "[PINDO_DEBUG] commit_log_id: #{commit_log_id}"
945
+ puts "[PINDO_DEBUG] fileUrls: #{result[:all_urls].inspect}"
946
+ end
947
+
948
+ error_detail = error_msg || "未知错误"
949
+ error_detail = "#{error_detail} (错误码: #{error_code})" if error_code
950
+ Funlog.instance.fancyinfo_error("更新失败: #{error_detail}")
874
951
  end
875
952
  rescue => e
876
- Funlog.instance.fancyinfo_error("更新提交记录失败: #{e.message}")
953
+ Funlog.instance.fancyinfo_error("更新失败: #{e.message}")
954
+ puts "[PINDO_DEBUG] 异常详情: #{e.class} - #{e.backtrace&.first}" if ENV['PINDO_DEBUG']
877
955
  end
878
956
  else
879
- Funlog.instance.warning("没有成功上传的文件,跳过更新提交记录")
957
+ Funlog.instance.warning("没有成功上传的文件")
880
958
  end
881
959
 
882
- # 8. 输出统计
883
- puts
884
- puts "上传统计:"
885
- puts " 成功: #{result[:success_urls].size} 个"
886
- puts " 失败: #{result[:failed_files].size} 个"
887
- puts " 总附件: #{result[:all_urls].size} 个"
960
+ # 9. 输出统计(简化,因为上面已经显示了上传结果)
961
+ if result[:all_urls].size > result[:success_urls].size
962
+ puts " 总附件数: #{result[:all_urls].size} 个(包含之前已有的 #{result[:existing_urls].size} 个)"
963
+ end
964
+ puts ""
888
965
 
889
966
  return result
890
967
  end
@@ -1460,6 +1537,19 @@ module Pindo
1460
1537
 
1461
1538
  end
1462
1539
 
1540
+ # 格式化文件大小
1541
+ # @param size [Integer] 字节数
1542
+ # @return [String] 格式化后的大小
1543
+ def format_file_size(size)
1544
+ if size < 1024
1545
+ "#{size}B"
1546
+ elsif size < 1024 * 1024
1547
+ "#{(size / 1024.0).round(1)}KB"
1548
+ else
1549
+ "#{(size / 1024.0 / 1024.0).round(1)}MB"
1550
+ end
1551
+ end
1552
+
1463
1553
  private
1464
1554
 
1465
1555
  # 确定 JPSBuildConfig.json 文件路径
@@ -1526,19 +1616,26 @@ module Pindo
1526
1616
  # @param app_info_obj [Hash] 项目信息对象
1527
1617
  # @param workflow_info [Hash] 工作流信息
1528
1618
  # @param package_type [String] 包类型 ("ipa" | "apk" | "zip")
1529
- def save_jps_build_config(working_directory:, app_info_obj:, workflow_info:, package_type:)
1530
- return if working_directory.nil? || app_info_obj.nil? || workflow_info.nil? || package_type.nil?
1619
+ def save_jps_build_config(working_directory:, app_info_obj:, workflow_info:, package_type:, manage_type: "")
1620
+ return if working_directory.nil? || app_info_obj.nil? || workflow_info.nil?
1531
1621
 
1532
1622
  # 1. 确定配置文件路径
1533
1623
  config_file = determine_config_file_path(working_directory)
1534
1624
 
1535
- # 2. 确定 workflow_key
1536
- workflow_key = case package_type
1537
- when 'ipa' then 'ipa_workflow'
1538
- when 'apk' then 'apk_workflow'
1539
- when 'zip' then 'webgl_workflow'
1540
- when 'app' then 'macos_workflow'
1541
- else raise Informative, "不支持的 package_type: #{package_type}"
1625
+ # 2. 根据 manage_type 或 package_type 确定 workflow_key
1626
+ workflow_key = nil
1627
+ if manage_type == "git"
1628
+ # manage_type git 时,使用 git_workflow
1629
+ workflow_key = 'git_workflow'
1630
+ else
1631
+ # package_type 确定 workflow_key
1632
+ workflow_key = case package_type
1633
+ when 'ipa' then 'ipa_workflow'
1634
+ when 'apk' then 'apk_workflow'
1635
+ when 'zip' then 'webgl_workflow'
1636
+ when 'app' then 'macos_workflow'
1637
+ else raise Informative, "不支持的 package_type: #{package_type}"
1638
+ end
1542
1639
  end
1543
1640
 
1544
1641
  # 3. 准备新的项目基础信息