pindo 5.17.5 → 5.18.4

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/git_handler.rb +120 -38
  3. data/lib/pindo/command/android/autobuild.rb +81 -40
  4. data/lib/pindo/command/appstore/adhocbuild.rb +1 -1
  5. data/lib/pindo/command/appstore/autobuild.rb +1 -1
  6. data/lib/pindo/command/appstore/autoresign.rb +1 -1
  7. data/lib/pindo/command/appstore/updateid.rb +229 -0
  8. data/lib/pindo/command/appstore.rb +1 -0
  9. data/lib/pindo/command/ios/autobuild.rb +70 -33
  10. data/lib/pindo/command/ios/podpush.rb +1 -1
  11. data/lib/pindo/command/jps/apptest.rb +2 -2
  12. data/lib/pindo/command/jps/bind.rb +1 -1
  13. data/lib/pindo/command/jps/media.rb +1 -1
  14. data/lib/pindo/command/jps/upload.rb +52 -22
  15. data/lib/pindo/command/unity/autobuild.rb +61 -44
  16. data/lib/pindo/command/utils/allcopyconfig.rb +144 -0
  17. data/lib/pindo/command/utils/copyconfig.rb +207 -0
  18. data/lib/pindo/command/utils/icon.rb +2 -2
  19. data/lib/pindo/command/utils/renewbundleid.rb +199 -0
  20. data/lib/pindo/command/utils/renewcert.rb +56 -54
  21. data/lib/pindo/command/utils.rb +3 -0
  22. data/lib/pindo/command/web/autobuild.rb +32 -26
  23. data/lib/pindo/config/build_info_manager.rb +1 -3
  24. data/lib/pindo/module/android/android_build_helper.rb +193 -33
  25. data/lib/pindo/module/android/android_config_helper.rb +305 -88
  26. data/lib/pindo/module/android/android_project_helper.rb +69 -14
  27. data/lib/pindo/module/android/android_res_helper.rb +349 -51
  28. data/lib/pindo/module/android/keystore_helper.rb +611 -295
  29. data/lib/pindo/module/android/workflow_gradle_injector.rb +702 -0
  30. data/lib/pindo/module/appselect.rb +4 -4
  31. data/lib/pindo/module/appstore/bundleid_helper.rb +204 -14
  32. data/lib/pindo/module/build/build_helper.rb +110 -10
  33. data/lib/pindo/module/build/git_repo_helper.rb +4 -4
  34. data/lib/pindo/module/cert/mode/base_cert_operator.rb +8 -6
  35. data/lib/pindo/module/pgyer/pgyerhelper.rb +105 -42
  36. data/lib/pindo/module/task/core/task_executor.rb +2 -0
  37. data/lib/pindo/module/task/model/build/android_build_dev_task.rb +64 -6
  38. data/lib/pindo/module/task/model/git/git_commit_task.rb +70 -54
  39. data/lib/pindo/module/task/model/git/git_tag_task.rb +13 -9
  40. data/lib/pindo/module/task/model/jps/jps_upload_task.rb +104 -1
  41. data/lib/pindo/module/task/model/unity/unity_export_task.rb +2 -1
  42. data/lib/pindo/module/task/model/unity/unity_update_task.rb +2 -1
  43. data/lib/pindo/module/task/model/unity/unity_yoo_asset_task.rb +2 -1
  44. data/lib/pindo/module/task/model/unity_task.rb +2 -1
  45. data/lib/pindo/module/task/task_manager.rb +8 -0
  46. data/lib/pindo/module/unity/unity_helper.rb +13 -10
  47. data/lib/pindo/module/unity/unity_proc_helper.rb +27 -2
  48. data/lib/pindo/module/xcode/applovin_xcode_helper.rb +4 -2
  49. data/lib/pindo/module/xcode/res/xcode_res_constant.rb +72 -0
  50. data/lib/pindo/module/xcode/xcode_build_config.rb +36 -17
  51. data/lib/pindo/module/xcode/xcode_build_helper.rb +180 -23
  52. data/lib/pindo/module/xcode/xcode_project_helper.rb +1 -1
  53. data/lib/pindo/module/xcode/xcode_res_helper.rb +32 -16
  54. data/lib/pindo/options/groups/build_options.rb +16 -5
  55. data/lib/pindo/options/groups/git_options.rb +7 -5
  56. data/lib/pindo/options/groups/unity_options.rb +11 -0
  57. data/lib/pindo/options/helpers/bundleid_selector.rb +25 -0
  58. data/lib/pindo/options/helpers/git_constants.rb +7 -6
  59. data/lib/pindo/version.rb +2 -2
  60. metadata +10 -5
@@ -0,0 +1,229 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'spaceship'
4
+ require 'pindo/options/options'
5
+ require 'pindo/module/appstore/bundleid_helper'
6
+ require 'pindo/base/git_handler'
7
+ require 'pindo/config/build_info_manager'
8
+
9
+ module Pindo
10
+ class Command
11
+ class Appstore < Command
12
+ class Updateid < Appstore
13
+
14
+ self.summary = '从Apple开发者中心同步bundle id的capabilities到config.json'
15
+
16
+ self.description = <<-DESC
17
+ 从Apple Developer Portal读取当前项目Bundle ID的Capability状态,
18
+ 写入config.json的capabilities字段并提交到Git仓库。
19
+
20
+ 支持功能:
21
+
22
+ * 读取主Bundle ID和所有Extension的Capability状态
23
+
24
+ * 自动识别App Group、iCloud容器的关联ID
25
+
26
+ * 将capabilities写入config.json并提交到Git仓库
27
+
28
+ * 支持dry-run预览模式
29
+
30
+ 使用示例:
31
+
32
+ $ pindo appstore updateid # 使用当前目录的config.json
33
+
34
+ $ pindo appstore updateid --config=config.json # 指定config.json路径
35
+
36
+ $ pindo appstore updateid --dry-run # 预览模式,不修改文件
37
+ DESC
38
+
39
+ self.arguments = [
40
+ CLAide::Argument.new('path/to/config.json', true)
41
+ ]
42
+
43
+ def self.option_items
44
+ @option_items ||= [
45
+ Pindo::Options::OptionItem.new(
46
+ key: :config,
47
+ description: '指定config.json文件路径',
48
+ type: String,
49
+ optional: true,
50
+ example: 'pindo appstore updateid --config=config.json'
51
+ ),
52
+ Pindo::Options::OptionItem.new(
53
+ key: :dry_run,
54
+ description: '预览模式,只显示差异不修改文件',
55
+ type: :boolean,
56
+ optional: true,
57
+ default_value: false,
58
+ example: 'pindo appstore updateid --dry-run'
59
+ )
60
+ ]
61
+ end
62
+
63
+ def self.options
64
+ option_items.map { |item| item.to_claide_option }.concat(super)
65
+ end
66
+
67
+ def initialize(argv)
68
+ positional_config = argv.shift_argument
69
+ @options = initialize_options(argv)
70
+ @config_path = @options[:config] || positional_config || File.join(Dir.pwd, 'config.json')
71
+ @dry_run = @options[:dry_run]
72
+ super
73
+ @additional_args = argv.remainder!
74
+ end
75
+
76
+ def validate!
77
+ super
78
+ unless File.exist?(@config_path)
79
+ help! "配置文件不存在: #{@config_path}"
80
+ end
81
+ begin
82
+ @config_json = JSON.parse(File.read(@config_path))
83
+ rescue JSON::ParserError => e
84
+ help! "配置文件格式错误: #{e.message}"
85
+ end
86
+
87
+ # 验证 app_identifier
88
+ app_info = @config_json['app_info']
89
+ if app_info.nil? || app_info['app_identifier'].nil? || app_info['app_identifier'].empty?
90
+ help! "config.json 中缺少 app_info.app_identifier"
91
+ end
92
+
93
+ # 验证 Apple ID
94
+ apple_id = @config_json.dig('account_info', 'apple_acount_id')
95
+ if apple_id.nil? || apple_id.empty? || apple_id.include?("__________")
96
+ help! "config.json 中缺少有效的 Apple ID (account_info.apple_acount_id)"
97
+ end
98
+ end
99
+
100
+ def run
101
+ begin
102
+ app_info = @config_json['app_info']
103
+ apple_id = @config_json.dig('account_info', 'apple_acount_id')
104
+
105
+ # 登录 Apple Developer Portal
106
+ puts "Login #{apple_id}..."
107
+ Spaceship.login(apple_id.to_s)
108
+ Spaceship.select_team
109
+
110
+ bundle_id = app_info['app_identifier']
111
+ puts
112
+ puts "读取 #{bundle_id} 的 Capability..."
113
+
114
+ # 读取主 Bundle ID 的 capabilities
115
+ capabilities = Pindo::BundleIdHelper.fetch_capabilities_from_portal(bundle_id: bundle_id)
116
+
117
+ if capabilities.nil?
118
+ puts "无法读取 #{bundle_id} 的 Capability,跳过"
119
+ return
120
+ end
121
+
122
+ # 显示读取到的 capabilities
123
+ capabilities.each do |key, value|
124
+ puts " #{key}: #{value.is_a?(String) ? "\"#{value}\"" : value}"
125
+ end
126
+
127
+ # 更新所有 Extension Bundle ID 的名称
128
+ puts
129
+ extension_keys = app_info.keys.select { |k| k.start_with?("app_identifier_") }
130
+ extension_keys.each do |key|
131
+ ext_bundle_id = app_info[key]
132
+ next if ext_bundle_id.nil? || ext_bundle_id.empty? || ext_bundle_id.include?("__________")
133
+
134
+ expected_name = Pindo::BundleIdHelper.generate_bundleid_name(ext_bundle_id)
135
+ ext_app = Spaceship::Portal.app.find(ext_bundle_id)
136
+ if ext_app.nil?
137
+ puts " #{ext_bundle_id} — Portal 中未找到,跳过"
138
+ next
139
+ end
140
+
141
+ if ext_app.name != expected_name
142
+ puts "Update #{ext_bundle_id} name: #{ext_app.name} -> #{expected_name}"
143
+ begin
144
+ ext_app.update_name!(expected_name)
145
+ rescue => e
146
+ puts " Portal 更新名称失败: #{e.message},尝试通过 API Key 更新..."
147
+ begin
148
+ Pindo::BundleIdHelper.update_bundleid_name(bundle_id: ext_bundle_id, new_name: expected_name)
149
+ rescue => e2
150
+ puts " 更新名称失败: #{e2.message}"
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ if @dry_run
157
+ # dry-run 模式:对比现有 capabilities 并显示差异
158
+ old_capabilities = app_info['capabilities'] || {}
159
+ puts
160
+ puts "[dry-run] 差异:"
161
+ has_diff = false
162
+ capabilities.each do |key, new_value|
163
+ old_value = old_capabilities[key]
164
+ if old_value.nil?
165
+ puts " + #{key}: #{new_value.is_a?(String) ? "\"#{new_value}\"" : new_value}"
166
+ has_diff = true
167
+ elsif old_value != new_value
168
+ old_display = old_value.is_a?(String) ? "\"#{old_value}\"" : old_value
169
+ new_display = new_value.is_a?(String) ? "\"#{new_value}\"" : new_value
170
+ puts " ~ #{key}: #{old_display} -> #{new_display}"
171
+ has_diff = true
172
+ end
173
+ end
174
+ old_capabilities.each do |key, old_value|
175
+ unless capabilities.key?(key)
176
+ old_display = old_value.is_a?(String) ? "\"#{old_value}\"" : old_value
177
+ puts " = #{key}: #{old_display} (保留)"
178
+ has_diff = true
179
+ end
180
+ end
181
+ puts " (无差异)" unless has_diff
182
+ puts
183
+ puts "[dry-run] 未修改任何文件"
184
+ else
185
+ # 获取 config 仓库目录并更新到最新(~/.pindo/{bundle_id}/)
186
+ app_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: bundle_id)
187
+ config_repo_file = File.join(app_config_dir, "config.json")
188
+
189
+ # 提交前先丢弃仓库中未跟踪的修改,确保干净状态
190
+ Pindo::GitHandler.git!(%W(-C #{app_config_dir} checkout -- config.json)) rescue nil
191
+
192
+ # 读取仓库中最新的 config.json 并更新 capabilities
193
+ repo_config_json = JSON.parse(File.read(config_repo_file))
194
+ repo_config_json['app_info']['capabilities'] = (repo_config_json['app_info']['capabilities'] || {}).merge(capabilities)
195
+
196
+ # 只写入 config.json 一个文件
197
+ File.open(config_repo_file, "w") do |f|
198
+ f.write(JSON.pretty_generate(repo_config_json) + "\n")
199
+ end
200
+
201
+ # 同时更新本地 config.json(如果路径不同)
202
+ if File.expand_path(@config_path) != File.expand_path(config_repo_file)
203
+ @config_json['app_info']['capabilities'] = (app_info['capabilities'] || {}).merge(capabilities)
204
+ File.open(@config_path, "w") do |f|
205
+ f.write(JSON.pretty_generate(@config_json) + "\n")
206
+ end
207
+ end
208
+
209
+ puts
210
+
211
+ # 只提交 config.json 到 Git 仓库
212
+ Pindo::GitHandler.git_addpush_repo(
213
+ path: app_config_dir,
214
+ message: "sync capabilities from Apple Developer Portal",
215
+ commit_file_params: ["config.json"]
216
+ )
217
+
218
+ puts "capabilities 已写入 config.json 并提交"
219
+ end
220
+ rescue StandardError => e
221
+ puts "\n updateid 失败: #{e.message}"
222
+ raise e
223
+ end
224
+ end
225
+
226
+ end
227
+ end
228
+ end
229
+ end
@@ -20,6 +20,7 @@ require 'pindo/command/appstore/configproj'
20
20
  require 'pindo/command/appstore/quswark'
21
21
  require 'pindo/command/appstore/quswauth'
22
22
  require 'pindo/command/appstore/tag'
23
+ require 'pindo/command/appstore/updateid'
23
24
 
24
25
  module Pindo
25
26
  class Command
@@ -158,27 +158,18 @@ module Pindo
158
158
 
159
159
  def validate!
160
160
  super # 基类的 HelpValidator 会统一处理 --help
161
-
162
- # 如果没有指定 bundleid,进行交互式选择
163
- if @args_bundle_id.nil? || @args_bundle_id.empty?
164
- @args_bundle_id = Pindo::Options::BundleIdSelector.select_bundleid(@build_type)
165
-
166
- # 如果用户取消选择或选择失败,报错
167
- if @args_bundle_id.nil? || @args_bundle_id.empty?
168
- help! "未选择有效的 Bundle ID"
169
- end
170
-
171
- # 重要:将交互式选择的值同步回 @options,确保能被缓存系统保存
172
- @options[:bundleid] = @args_bundle_id
173
- end
161
+ # bundle_id 校验推迟到 run 中,在 load_jps_build_config 之后解析
174
162
  end
175
163
 
176
164
  def run
177
165
  pindo_project_dir = Dir.pwd
178
166
 
179
167
  begin
180
- # 加载 JPS 配置(如果存在)
181
- Pindo::BuildHelper.share_instance.load_jps_build_config(pindo_project_dir)
168
+ # 加载 JPS 配置(缓存 project_name,并通过映射表解析 bundle_id)
169
+ Pindo::BuildHelper.share_instance.load_jps_build_config(pindo_project_dir, conf: @args_conf)
170
+
171
+ # 解析 bundle_id(优先级:命令行参数 > JPSBuildConfig映射 > 交互选择)
172
+ resolve_bundle_id!
182
173
 
183
174
  # 准备配置
184
175
  config = prepare_ios_config(pindo_project_dir)
@@ -207,6 +198,44 @@ module Pindo
207
198
 
208
199
  private
209
200
 
201
+ # 解析 bundle_id(优先级:命令行参数 > JPSBuildConfig映射 > prepare_upload交互选择)
202
+ def resolve_bundle_id!
203
+ # 优先级 1:命令行 --bundleid 参数
204
+ return if @args_bundle_id && !@args_bundle_id.empty?
205
+
206
+ # 优先级 2:JPSBuildConfig.json 通过映射表解析的 bundle_id
207
+ resolved = Pindo::Options::GlobalOptionsState.instance[:bundleid]
208
+ if resolved && !resolved.empty?
209
+ @args_bundle_id = resolved
210
+ return
211
+ end
212
+
213
+ # 优先级 3:走 prepare_upload 交互选择 JPS 项目,创建/更新 JPSBuildConfig.json
214
+ pindo_project_dir = Dir.pwd
215
+ is_macos = Pindo::BuildHelper.share_instance.macos_project?(pindo_project_dir)
216
+ package_type = is_macos ? 'mac' : 'ipa'
217
+
218
+ @cached_app_info_obj, @cached_workflow_info = PgyerHelper.share_instace.prepare_upload(
219
+ working_directory: pindo_project_dir,
220
+ conf: @args_conf,
221
+ package_type: package_type
222
+ )
223
+
224
+ # prepare_upload 已创建 JPSBuildConfig.json,重新加载获取 bundle_id
225
+ Pindo::BuildHelper.share_instance.load_jps_build_config(pindo_project_dir, conf: @args_conf)
226
+ resolved = Pindo::Options::GlobalOptionsState.instance[:bundleid]
227
+ if resolved && !resolved.empty?
228
+ @args_bundle_id = resolved
229
+ return
230
+ end
231
+
232
+ # 最终降级:交互选择 bundle_id
233
+ @args_bundle_id = Pindo::Options::BundleIdSelector.select_bundleid(@build_type)
234
+ if @args_bundle_id.nil? || @args_bundle_id.empty?
235
+ raise Informative, "未选择有效的 Bundle ID"
236
+ end
237
+ end
238
+
210
239
  # 创建构建任务
211
240
  def make_build_task(config)
212
241
  # 检测项目类型
@@ -316,12 +345,15 @@ module Pindo
316
345
  build_task.dependencies << tasks.last.id if tasks.any?
317
346
  tasks << build_task
318
347
 
319
- # 4. Git 标签任务(依赖第一个编译任务)
320
- # 所有参数都从 GitCommitTask 获取
321
- git_tag_task = Pindo::TaskSystem::GitTagTask.new(config[:project_path])
322
- git_tag_task.dependencies << build_task.id
323
- git_tag_task.dependencies << git_commit_task.id
324
- tasks << git_tag_task
348
+ # 4. Git 标签任务(skip_without_tag 模式下不创建)
349
+ git_tag_task = nil
350
+ unless process_type == Pindo::UncommittedFilesProcessType::SKIP_WITHOUT_TAG
351
+ # 所有参数都从 GitCommitTask 获取
352
+ git_tag_task = Pindo::TaskSystem::GitTagTask.new(config[:project_path])
353
+ git_tag_task.dependencies << build_task.id
354
+ git_tag_task.dependencies << git_commit_task.id
355
+ tasks << git_tag_task
356
+ end
325
357
 
326
358
  # 5. 上传和消息发送任务(如果需要)
327
359
  upload_task = nil # 声明变量以便后续绑定任务使用
@@ -421,7 +453,7 @@ module Pindo
421
453
  )
422
454
  # 依赖 Git Commit、Git Tag 和 Bind Package 任务
423
455
  workflow_message_task.dependencies << git_commit_task.id
424
- workflow_message_task.dependencies << git_tag_task.id
456
+ workflow_message_task.dependencies << git_tag_task.id if git_tag_task
425
457
  workflow_message_task.dependencies << bind_package_task.id
426
458
  tasks << workflow_message_task
427
459
  end
@@ -440,17 +472,22 @@ module Pindo
440
472
  # 拉取并加载配置文件到 IosConfigParser
441
473
  load_config_file(pindo_project_dir, bundle_id)
442
474
 
443
- # 获取 JPS 配置
444
- # 根据 Xcode 工程类型动态设置 package_type
445
- # JPSUploadTask 支持的文件类型:'ipa' | 'apk' | 'html' | 'mac'
446
- is_macos = Pindo::BuildHelper.share_instance.macos_project?(pindo_project_dir)
447
- package_type = is_macos ? 'mac' : 'ipa'
448
-
449
- app_info_obj, workflow_info = PgyerHelper.share_instace.prepare_upload(
450
- working_directory: pindo_project_dir,
451
- conf: @args_conf,
452
- package_type: package_type
453
- )
475
+ # 获取 JPS 配置(复用 resolve_bundle_id! 中已缓存的结果)
476
+ if @cached_app_info_obj && @cached_workflow_info
477
+ app_info_obj = @cached_app_info_obj
478
+ workflow_info = @cached_workflow_info
479
+ else
480
+ # 根据 Xcode 工程类型动态设置 package_type
481
+ # JPSUploadTask 支持的文件类型:'ipa' | 'apk' | 'html' | 'mac'
482
+ is_macos = Pindo::BuildHelper.share_instance.macos_project?(pindo_project_dir)
483
+ package_type = is_macos ? 'mac' : 'ipa'
484
+
485
+ app_info_obj, workflow_info = PgyerHelper.share_instace.prepare_upload(
486
+ working_directory: pindo_project_dir,
487
+ conf: @args_conf,
488
+ package_type: package_type
489
+ )
490
+ end
454
491
 
455
492
  {
456
493
  project_path: pindo_project_dir,
@@ -193,7 +193,7 @@ module Pindo
193
193
  git!(%W(-C #{private_source.repo} reset --hard))
194
194
  git!(%W(-C #{private_source.repo} clean -dfx))
195
195
  git!(%W(-C #{private_source.repo} branch --set-upstream-to=origin/#{private_source_branch} #{private_source_branch}))
196
- git!(%W(-C #{private_source.repo} pull))
196
+ Pindo::GitHandler.git_remote!(private_source.repo, %W(-C #{private_source.repo} pull))
197
197
  rescue StandardError => e
198
198
  raise Informative, "私有Pod索引目录异常,请删除#{private_source.repo}重新新下载"
199
199
  end
@@ -172,7 +172,7 @@ module Pindo
172
172
  tasks.each { |task| task_manager.add_task(task) }
173
173
  task_manager.start
174
174
 
175
- # 6. 输出结果
175
+ # 6. 输出结果(任务失败时 start 会自动抛出异常;这里仍要求至少成功一个任务)
176
176
  report = task_manager.execution_report
177
177
  if report[:success] > 0
178
178
  puts "\n✅ 消息发送完成!"
@@ -184,4 +184,4 @@ module Pindo
184
184
  end
185
185
  end
186
186
  end
187
- end
187
+ end
@@ -165,7 +165,7 @@ module Pindo
165
165
  tasks.each { |task| task_manager.add_task(task) }
166
166
  task_manager.start
167
167
 
168
- # 7. 输出结果
168
+ # 7. 输出结果(任务失败时 start 会自动抛出异常;这里仍要求至少成功一个任务)
169
169
  report = task_manager.execution_report
170
170
  if report[:success] > 0
171
171
  puts "\n✅ 绑定完成! 成功绑定 #{app_version_list.size} 个包到 Git Workflow"
@@ -162,7 +162,7 @@ module Pindo
162
162
  tasks.each { |task| task_manager.add_task(task) }
163
163
  task_manager.start
164
164
 
165
- # 输出结果
165
+ # 输出结果(任务失败时 start 会自动抛出异常;这里仍要求至少成功一个任务)
166
166
  report = task_manager.execution_report
167
167
  if report[:success] > 0
168
168
  puts "\n上传完成!"
@@ -25,7 +25,8 @@ module Pindo
25
25
  支持功能:
26
26
 
27
27
  * 上传ipa/apk/app/exe/html安装包
28
- * Unity工程自动检测iOS/Android/WebGL/Windows包
28
+ * Unity工程自动检测iOS/Android/WebGL/macOS/Windows包
29
+ * 通过 --types 指定要上传的包类型(与 unity autobuild 一致)
29
30
  * 添加版本描述
30
31
  * 上传附件
31
32
  * 重签名
@@ -37,6 +38,12 @@ module Pindo
37
38
 
38
39
  $ pindo jps upload path/to/setup.exe # 上传 Windows 安装包
39
40
 
41
+ $ pindo jps upload --types=ipa # 仅上传 IPA
42
+
43
+ $ pindo jps upload --types=ipa,apk # 上传 IPA 和 APK
44
+
45
+ $ pindo jps upload --types=html # 仅上传 WebGL
46
+
40
47
  $ pindo jps upload --proj=demo # 上传到指定项目
41
48
 
42
49
  $ pindo jps upload --desc="版本说明" # 添加版本描述
@@ -59,6 +66,7 @@ module Pindo
59
66
  # 定义此命令使用的参数项
60
67
  def self.option_items
61
68
  @option_items ||= Pindo::Options::OptionGroup.merge(
69
+ Pindo::Options::BuildOptions.select(:types),
62
70
  Pindo::Options::JPSOptions.select(:conf, :send, :desc, :resign),
63
71
  Pindo::Options::GitOptions.all
64
72
  )
@@ -67,18 +75,18 @@ module Pindo
67
75
  def self.options
68
76
  [
69
77
  ['--login', '强制再次登录jps网站'],
70
- ['--ipa', '强制指定上传的ipa文件'],
71
- ['--attach', '指定需要和ipa一起上传的附件'],
78
+ ['--file', '指定要上传的文件路径(支持 ipa/apk/app/exe/html)'],
79
+ ['--attach', '指定需要和安装包一起上传的附件'],
72
80
  ].concat(option_items.map(&:to_claide_option)).concat(super)
73
81
  end
74
82
 
75
83
 
76
84
  def initialize(argv)
77
85
  @args_ipa_file = argv.shift_argument
78
- @ipa_file = argv.option('ipa')
86
+ file_option = argv.option('file') || argv.option('ipa')
79
87
 
80
- if !@ipa_file.nil?
81
- @args_ipa_file = @ipa_file
88
+ if !file_option.nil?
89
+ @args_ipa_file = file_option
82
90
  end
83
91
  if @args_ipa_file && !@args_ipa_file.empty?
84
92
  @args_ipa_file = @args_ipa_file.strip.gsub(/\"/, '')
@@ -90,6 +98,8 @@ module Pindo
90
98
  # 使用 Options 系统解析参数
91
99
  @options = initialize_options(argv)
92
100
 
101
+ @args_types = @options[:types]
102
+
93
103
  # JPS 参数
94
104
  @args_conf = @options[:conf]
95
105
  @args_send_flag = @options[:send] || false
@@ -283,22 +293,39 @@ module Pindo
283
293
  end
284
294
  end
285
295
 
296
+ # 解析 --types 参数,返回允许的类型数组,nil 表示不限制
297
+ def parse_types_filter
298
+ return nil unless @args_types
299
+
300
+ available_types = %w[ipa apk html mac exe]
301
+ types = @args_types.downcase.split(',').map(&:strip)
302
+
303
+ invalid_types = types - available_types
304
+ unless invalid_types.empty?
305
+ raise Informative, "无效的包类型: #{invalid_types.join(', ')}。可用类型: #{available_types.join(', ')}"
306
+ end
307
+
308
+ types
309
+ end
310
+
286
311
  # 查找并确认 Unity 包(可能有多个平台)
287
312
  def find_and_confirm_unity_packages(project_dir, tasks)
313
+ types_filter = parse_types_filter
314
+
288
315
  # 1. 查找所有平台的文件
289
- ios_file = find_unity_ios_package(project_dir)
290
- macos_file = find_unity_macos_package(project_dir)
291
- android_file = find_unity_android_package(project_dir)
292
- webgl_file = find_unity_webgl_package(project_dir)
293
- windows_file = find_unity_windows_package(project_dir)
294
-
295
- # 2. 收集找到的文件
296
- found_files = []
297
- found_files << { file: ios_file, type: 'ipa', name: 'iOS' } if ios_file
298
- found_files << { file: macos_file, type: 'mac', name: 'macOS' } if macos_file
299
- found_files << { file: android_file, type: 'apk', name: 'Android' } if android_file
300
- found_files << { file: webgl_file, type: 'html', name: 'WebGL' } if webgl_file
301
- found_files << { file: windows_file, type: 'exe', name: 'Windows' } if windows_file
316
+ all_candidates = [
317
+ { file: find_unity_ios_package(project_dir), type: 'ipa', name: 'iOS' },
318
+ { file: find_unity_macos_package(project_dir), type: 'mac', name: 'macOS' },
319
+ { file: find_unity_android_package(project_dir), type: 'apk', name: 'Android' },
320
+ { file: find_unity_webgl_package(project_dir), type: 'html', name: 'WebGL' },
321
+ { file: find_unity_windows_package(project_dir), type: 'exe', name: 'Windows' }
322
+ ]
323
+
324
+ # 2. 过滤:去掉未找到的文件,按 --types 过滤
325
+ found_files = all_candidates.select { |info| info[:file] }
326
+ if types_filter
327
+ found_files = found_files.select { |info| types_filter.include?(info[:type]) }
328
+ end
302
329
 
303
330
  # 3. 如果没有找到任何文件,直接返回
304
331
  return if found_files.empty?
@@ -440,10 +467,13 @@ module Pindo
440
467
  windows_files.max_by {|f| File.mtime(f)} if windows_files.any?
441
468
  end
442
469
 
443
- # 确认文件(交互式)
470
+ # 确认文件(交互式,设置 PINDO_AUTO_CONFIRM 时自动确认)
444
471
  def confirm_file(file_path)
445
- answer = agree("需要上传文件: #{file_path} ?(Y/n)")
446
- answer
472
+ if ENV['PINDO_AUTO_CONFIRM'] && !ENV['PINDO_AUTO_CONFIRM'].empty?
473
+ puts "自动确认上传文件: #{file_path}"
474
+ return true
475
+ end
476
+ agree("需要上传文件: #{file_path} ?(Y/n)")
447
477
  end
448
478
 
449
479
  # 根据文件扩展名确定文件类型