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