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
@@ -3,7 +3,10 @@ require 'fileutils'
3
3
  require 'json'
4
4
  require 'faraday'
5
5
  require 'pindo/module/pgyer/pgyerhelper'
6
+ require 'pindo/module/build/git_repo_helper'
6
7
  require 'pindo/module/build/build_helper'
8
+ require 'pindo/module/task/task_manager'
9
+ require 'pindo/module/task/model/upload_task'
7
10
 
8
11
  module Pindo
9
12
  class Command
@@ -104,112 +107,280 @@ module Pindo
104
107
  end
105
108
 
106
109
  def run
107
-
108
110
  current_project_dir = Dir.pwd
109
- build_helper = Pindo::BuildHelper.share_instance
110
111
 
111
- Dir.chdir(current_project_dir)
112
- is_need_add_tag,tag_action_parms = build_helper.check_is_need_add_tag?(current_project_dir)
112
+ # 创建任务列表
113
+ tasks = make_upload_tasks(current_project_dir)
114
+
115
+ # 执行任务
116
+ task_manager = Pindo::TaskSystem::TaskManager.instance
117
+ task_manager.clear_all
118
+ tasks.each { |task| task_manager.add_task(task) }
119
+ task_manager.start
120
+
121
+ # 如果需要重签名,在所有上传任务完成后执行
122
+ if @args_resign_flag
123
+ args = []
124
+ if @args_send_flag
125
+ args << "--send"
126
+ end
127
+ if !@args_cert_id.nil? && !@args_cert_id.empty?
128
+ args << "--certid=#{@args_cert_id}"
129
+ end
130
+ if !@args_proj_name.nil? && !@args_proj_name.empty?
131
+ args << "--proj=#{@args_proj_name}"
132
+ end
133
+ Pindo::Command::Jps::Resign::run(args)
134
+ end
135
+ end
136
+
137
+ private
138
+
139
+ # 创建上传任务列表
140
+ def make_upload_tasks(project_dir)
141
+ tasks = []
142
+
143
+ # 1. Git Tag 任务(检查并添加标签)
144
+ git_repo_helper = Pindo::GitRepoHelper.share_instance
145
+ Dir.chdir(project_dir)
146
+ is_need_add_tag, tag_action_parms = git_repo_helper.check_is_need_add_tag?(project_dir)
113
147
  if is_need_add_tag
114
- Pindo::Command::Utils::Tag::run(tag_action_parms)
148
+ git_repo_helper.create_and_push_tag(
149
+ project_dir: project_dir,
150
+ mode: 'minor',
151
+ force_retag: tag_action_parms&.include?('--retag') || false,
152
+ custom_tag: nil,
153
+ release_branch: 'master'
154
+ )
115
155
  end
116
156
 
117
- if @args_ipa_file.nil? || !File.exist?(@args_ipa_file)
118
- # 获取build目录下的ipa文件
119
- project_type = build_helper.project_type(current_project_dir)
120
- case project_type
121
- when :ios
122
- build_path = File.join(current_project_dir, "build", "*.{ipa,app}")
123
- @args_ipa_file = Dir.glob(build_path).max_by {|f| File.mtime(f)}
124
- when :android
125
- # 搜索 build 目录下的所有 apk 文件(包括子目录)
126
- build_path = File.join(current_project_dir, "build", "**", "*.{apk}")
127
- @args_ipa_file = Dir.glob(build_path).max_by {|f| File.mtime(f)}
128
- when :unity
129
- # Unity 工程支持三种平台的包:iOS、Android 和 WebGL
130
- all_packages = []
131
-
132
- # 检测 iOS 包(收集所有 iOS 包)
133
- if File.exist?(File.join(current_project_dir, "GoodPlatform/BaseiOS/build"))
134
- ios_build_path = File.join(current_project_dir, "GoodPlatform/BaseiOS/build", "*.{ipa,app}")
135
- all_packages.concat(Dir.glob(ios_build_path))
136
- end
157
+ # 2. 查找并创建上传任务
158
+ upload_tasks = find_and_create_upload_tasks(project_dir)
159
+ tasks.concat(upload_tasks)
137
160
 
138
- if File.exist?(File.join(current_project_dir, "GoodPlatform/iOS/build"))
139
- ios_build_path = File.join(current_project_dir, "GoodPlatform/iOS/build", "*.{ipa,app}")
140
- all_packages.concat(Dir.glob(ios_build_path))
141
- end
161
+ tasks
162
+ end
142
163
 
143
- # 检测 Android 包(收集所有 Android 包,包括子目录)
144
- if File.exist?(File.join(current_project_dir, "GoodPlatform/BaseAndroid/build"))
145
- android_build_path = File.join(current_project_dir, "GoodPlatform/BaseAndroid/build", "**", "*.{apk,aab}")
146
- all_packages.concat(Dir.glob(android_build_path))
147
- end
164
+ # 查找文件并创建上传任务
165
+ def find_and_create_upload_tasks(project_dir)
166
+ tasks = []
148
167
 
149
- if File.exist?(File.join(current_project_dir, "GoodPlatform/Android/build"))
150
- android_build_path = File.join(current_project_dir, "GoodPlatform/Android/build", "**", "*.{apk,aab}")
151
- all_packages.concat(Dir.glob(android_build_path))
152
- end
168
+ # 如果用户指定了文件,直接创建上传任务
169
+ if @args_ipa_file && !@args_ipa_file.empty? && File.exist?(@args_ipa_file)
170
+ file_type = determine_file_type(@args_ipa_file)
171
+ tasks << create_upload_task(file_type, project_dir, @args_ipa_file)
172
+ return tasks
173
+ end
153
174
 
154
- # 检测 WebGL 包(HTML 文件)
155
- if File.exist?(File.join(current_project_dir, "GoodPlatform/WebGL/build"))
156
- webgl_build_path = File.join(current_project_dir, "GoodPlatform/WebGL/build", "index.html")
157
- webgl_files = Dir.glob(webgl_build_path)
158
- all_packages.concat(webgl_files)
159
- end
175
+ # 根据项目类型查找文件
176
+ build_helper = Pindo::BuildHelper.share_instance
177
+ project_type = build_helper.project_type(project_dir)
178
+
179
+ case project_type
180
+ when :ios
181
+ find_and_confirm_ios_package(project_dir, tasks)
182
+ when :android
183
+ find_and_confirm_android_package(project_dir, tasks)
184
+ when :unity
185
+ find_and_confirm_unity_packages(project_dir, tasks)
186
+ else
187
+ # 不是工程目录,尝试在根目录查找
188
+ find_and_confirm_fallback_package(project_dir, tasks)
189
+ end
160
190
 
161
- # 从所有找到的包中选择最新的一个
162
- if all_packages.length > 0
163
- # 选择修改时间最新的文件
164
- @args_ipa_file = all_packages.max_by {|f| File.mtime(f)}
191
+ # 如果没有找到任何文件,让用户手动输入
192
+ if tasks.empty?
193
+ manual_file = ask('需要上传的文件:') || nil
194
+ if manual_file && !manual_file.empty?
195
+ manual_file = manual_file.strip.gsub(/\\ /, ' ')
196
+ if File.exist?(manual_file)
197
+ file_type = determine_file_type(manual_file)
198
+ tasks << create_upload_task(file_type, File.dirname(manual_file), manual_file)
165
199
  else
166
- @args_ipa_file = nil
200
+ raise Informative, "#{manual_file} 文件不存在"
167
201
  end
168
- else
169
- raise Informative, "当前目录不是工程目录,不能编译"
170
202
  end
203
+ end
171
204
 
205
+ if tasks.empty?
206
+ raise Informative, "未找到可上传的文件"
207
+ end
172
208
 
173
- if @args_ipa_file.nil?
174
- build_path = File.join(current_project_dir, "*.{ipa,app,apk,html}")
175
- @args_ipa_file = Dir.glob(build_path).max_by {|f| File.mtime(f)}
176
- end
209
+ tasks
210
+ end
177
211
 
178
- if !@args_ipa_file.nil?
179
- answer = agree("需要上传的文件是: #{@args_ipa_file} ?(Y/n)")
180
- if !answer
181
- @args_ipa_file = nil
182
- end
212
+ # 查找并确认 iOS/macOS 包
213
+ def find_and_confirm_ios_package(project_dir, tasks)
214
+ # 判断是 macOS 还是 iOS 工程
215
+ build_helper = Pindo::BuildHelper.share_instance
216
+ is_macos = build_helper.macos_project?(project_dir)
217
+
218
+ if is_macos
219
+ # macOS 工程查找 .app 文件
220
+ macos_file = find_macos_package(project_dir)
221
+ if macos_file && confirm_file(macos_file)
222
+ tasks << create_upload_task('app', File.dirname(macos_file), macos_file)
223
+ end
224
+ else
225
+ # iOS 工程查找 .ipa 文件
226
+ ios_file = find_ios_package(project_dir)
227
+ if ios_file && confirm_file(ios_file)
228
+ tasks << create_upload_task('ipa', File.dirname(ios_file), ios_file)
183
229
  end
230
+ end
231
+ end
232
+
233
+ # 查找并确认 Android 包
234
+ def find_and_confirm_android_package(project_dir, tasks)
235
+ android_file = find_android_package(project_dir)
236
+ if android_file && confirm_file(android_file)
237
+ tasks << create_upload_task('apk', File.dirname(android_file), android_file)
238
+ end
239
+ end
240
+
241
+ # 查找并确认 Unity 包(可能有多个平台)
242
+ def find_and_confirm_unity_packages(project_dir, tasks)
243
+ # 1. 查找所有平台的文件
244
+ ios_file = find_unity_ios_package(project_dir)
245
+ android_file = find_unity_android_package(project_dir)
246
+ webgl_file = find_unity_webgl_package(project_dir)
247
+
248
+ # 2. 收集找到的文件
249
+ found_files = []
250
+ found_files << { file: ios_file, type: 'ipa', name: 'iOS' } if ios_file
251
+ found_files << { file: android_file, type: 'apk', name: 'Android' } if android_file
252
+ found_files << { file: webgl_file, type: 'html', name: 'WebGL' } if webgl_file
253
+
254
+ # 3. 如果没有找到任何文件,直接返回
255
+ return if found_files.empty?
256
+
257
+ # 4. 输出找到的所有文件
258
+ puts "\n找到以下 Unity 构建文件:"
259
+ found_files.each_with_index do |info, index|
260
+ puts " #{index + 1}. [#{info[:name]}] #{info[:file]}"
261
+ end
262
+ puts ""
184
263
 
185
- if !@args_ipa_file.nil? && File.exist?(@args_ipa_file)
186
- else
187
- @args_ipa_file = ask('需要上传的文件:') || nil
188
- @args_ipa_file = @args_ipa_file.strip.gsub(/\\ /, ' ')
264
+ # 5. 逐个确认是否上传
265
+ found_files.each do |info|
266
+ if confirm_file(info[:file])
267
+ tasks << create_upload_task(info[:type], File.dirname(info[:file]), info[:file])
189
268
  end
190
269
  end
270
+ end
271
+
272
+ # 在项目根目录查找包(兜底)
273
+ def find_and_confirm_fallback_package(project_dir, tasks)
274
+ build_path = File.join(project_dir, "*.{ipa,app,apk,html}")
275
+ file = Dir.glob(build_path).max_by {|f| File.mtime(f)}
276
+ if file && confirm_file(file)
277
+ file_type = determine_file_type(file)
278
+ tasks << create_upload_task(file_type, File.dirname(file), file)
279
+ end
280
+ end
281
+
282
+ # 查找 iOS 包
283
+ def find_ios_package(project_dir)
284
+ build_path = File.join(project_dir, "build", "*.ipa")
285
+ Dir.glob(build_path).max_by {|f| File.mtime(f)}
286
+ end
287
+
288
+ # 查找 macOS 包
289
+ def find_macos_package(project_dir)
290
+ build_path = File.join(project_dir, "build", "*.app")
291
+ Dir.glob(build_path).max_by {|f| File.mtime(f)}
292
+ end
293
+
294
+ # 查找 Android 包
295
+ def find_android_package(project_dir)
296
+ build_path = File.join(project_dir, "build", "**", "*.{apk}")
297
+ Dir.glob(build_path).max_by {|f| File.mtime(f)}
298
+ end
299
+
300
+ # 查找 Unity iOS 包
301
+ def find_unity_ios_package(project_dir)
302
+ ios_files = []
303
+
304
+ # 检测 BaseiOS
305
+ base_ios_dir = File.join(project_dir, "GoodPlatform/BaseiOS/build")
306
+ if File.exist?(base_ios_dir)
307
+ build_path = File.join(base_ios_dir, "*.{ipa,app}")
308
+ ios_files.concat(Dir.glob(build_path))
309
+ end
310
+
311
+ # 检测 iOS
312
+ ios_dir = File.join(project_dir, "GoodPlatform/iOS/build")
313
+ if File.exist?(ios_dir)
314
+ build_path = File.join(ios_dir, "*.{ipa,app}")
315
+ ios_files.concat(Dir.glob(build_path))
316
+ end
317
+
318
+ ios_files.max_by {|f| File.mtime(f)} if ios_files.any?
319
+ end
320
+
321
+ # 查找 Unity Android 包
322
+ def find_unity_android_package(project_dir)
323
+ android_files = []
324
+
325
+ # 检测 BaseAndroid
326
+ base_android_dir = File.join(project_dir, "GoodPlatform/BaseAndroid/build")
327
+ if File.exist?(base_android_dir)
328
+ build_path = File.join(base_android_dir, "**", "*.{apk}")
329
+ android_files.concat(Dir.glob(build_path))
330
+ end
331
+
332
+ # 检测 Android
333
+ android_dir = File.join(project_dir, "GoodPlatform/Android/build")
334
+ if File.exist?(android_dir)
335
+ build_path = File.join(android_dir, "**", "*.{apk}")
336
+ android_files.concat(Dir.glob(build_path))
337
+ end
338
+
339
+ android_files.max_by {|f| File.mtime(f)} if android_files.any?
340
+ end
191
341
 
192
- if !File.exist?(@args_ipa_file)
193
- raise Informative, "#{@args_ipa_file} 文件不存在"
342
+ # 查找 Unity WebGL 包
343
+ def find_unity_webgl_package(project_dir)
344
+ webgl_dir = File.join(project_dir, "GoodPlatform/WebGL/build")
345
+ if File.exist?(webgl_dir)
346
+ webgl_file = File.join(webgl_dir, "index.html")
347
+ return webgl_file if File.exist?(webgl_file)
194
348
  end
349
+ nil
350
+ end
195
351
 
196
- # 根据文件后缀确定 package_type
197
- package_type = nil
198
- ext = File.extname(@args_ipa_file).downcase
352
+ # 确认文件(交互式)
353
+ def confirm_file(file_path)
354
+ answer = agree("需要上传文件: #{file_path} ?(Y/n)")
355
+ answer
356
+ end
357
+
358
+ # 根据文件扩展名确定文件类型
359
+ def determine_file_type(file_path)
360
+ ext = File.extname(file_path).downcase
199
361
  case ext
200
362
  when '.ipa'
201
- package_type = 'ipa'
363
+ 'ipa'
202
364
  when '.apk'
203
- package_type = 'apk'
365
+ 'apk'
204
366
  when '.html'
205
- package_type = 'zip'
367
+ 'html'
206
368
  when '.app'
207
- package_type = 'mac'
369
+ 'app'
208
370
  else
209
371
  raise Informative, "不支持的文件类型: #{ext},支持的类型:.ipa, .apk, .html, .app"
210
372
  end
373
+ end
211
374
 
212
- PgyerHelper.share_instace.setForeLogin(beforeLogin:@args_login_flag)
375
+ # 创建上传任务
376
+ def create_upload_task(file_type, upload_path, upload_file)
377
+ # 设置 PgyerHelper 登录选项
378
+ PgyerHelper.share_instace.setForeLogin(beforeLogin: @args_login_flag)
379
+
380
+ # 根据 file_type 确定 package_type(用于获取 JPS 配置)
381
+ package_type = file_type == 'html' ? 'zip' : file_type
382
+
383
+ # 提前获取 JPS 配置(app_info_obj 和 workflow_info)
213
384
  app_info_obj, workflow_info = PgyerHelper.share_instace.prepare_upload(
214
385
  working_directory: Dir.pwd,
215
386
  proj_name: @args_proj_name,
@@ -220,53 +391,22 @@ module Pindo
220
391
  raise Informative, "#{@args_proj_name} 错误, 请输入正确的App代号名称, jps网站没有该App"
221
392
  end
222
393
 
223
- result_data = PgyerHelper.share_instace.start_upload(
394
+ # 创建 UploadTask
395
+ Pindo::TaskSystem::UploadTask.new(
396
+ file_type,
397
+ upload_path,
398
+ upload_file,
224
399
  app_info_obj: app_info_obj,
225
- ipa_file_upload: @args_ipa_file,
226
- description: @args_upload_desc,
227
- workflow_info: workflow_info
400
+ workflow_info: workflow_info,
401
+ project_name: @args_proj_name,
402
+ context: {
403
+ upload_desc: @args_upload_desc,
404
+ send_to_chat: @args_send_flag
405
+ }
228
406
  )
229
- if !result_data.nil? && !result_data["data"].nil? && !result_data["data"]["id"].nil?
230
- PgyerHelper.share_instace.print_app_version_info(
231
- app_info_obj: app_info_obj,
232
- app_version_info_obj: result_data["data"]
233
- )
234
-
235
- if @args_resign_flag
236
- args = []
237
- if @args_send_flag
238
- args << "--send"
239
- end
240
- if !@args_cert_id.nil? && !@args_cert_id.empty?
241
- args << "--certid=#{@args_cert_id}"
242
- end
243
- if !@args_proj_name.nil? && !@args_proj_name.empty?
244
- args << "--proj=#{@args_proj_name}"
245
- end
246
- Pindo::Command::Jps::Resign::run(args)
247
- else
248
- # 始终发送给自己
249
- PgyerHelper.share_instace.send_apptest_msg(
250
- app_info_obj: app_info_obj,
251
- app_version_info_obj: result_data["data"],
252
- receiveType: "self"
253
- )
254
-
255
- # 如果有 --send 参数,额外发送到测试群
256
- if @args_send_flag
257
- PgyerHelper.share_instace.send_apptest_msg(
258
- app_info_obj: app_info_obj,
259
- app_version_info_obj: result_data["data"],
260
- chatEnv: "DevTest",
261
- receiveType: "chat"
262
- )
263
- end
264
- end
265
- end
266
-
267
407
  end
268
408
 
269
409
  end
270
410
  end
271
411
  end
272
- end
412
+ end