pindo 5.18.17 → 5.19.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/git_handler.rb +44 -83
  3. data/lib/pindo/command/appstore/adhocbuild.rb +13 -2
  4. data/lib/pindo/command/appstore/autobuild.rb +2 -1
  5. data/lib/pindo/command/appstore/iap.rb +58 -54
  6. data/lib/pindo/command/repo/create.rb +1 -1
  7. data/lib/pindo/command/repo/search.rb +1 -1
  8. data/lib/pindo/command/utils/installskills.rb +2 -2
  9. data/lib/pindo/command/utils/renewproj.rb +0 -1
  10. data/lib/pindo/config/build_info_manager.rb +31 -0
  11. data/lib/pindo/config/ios_config_parser.rb +212 -140
  12. data/lib/pindo/module/android/android_build_helper.rb +39 -16
  13. data/lib/pindo/module/android/gradle_helper.rb +8 -14
  14. data/lib/pindo/module/appstore/appstore_in_app_purchase.rb +80 -56
  15. data/lib/pindo/module/cert/cert_helper.rb +2 -2
  16. data/lib/pindo/module/pgyer/pgyerhelper.rb +18 -20
  17. data/lib/pindo/module/task/model/build/android_build_dev_task.rb +1 -37
  18. data/lib/pindo/module/task/model/build/android_build_task.rb +40 -0
  19. data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +9 -35
  20. data/lib/pindo/module/task/model/build/ios_build_appstore_task.rb +5 -5
  21. data/lib/pindo/module/task/model/build/ios_build_dev_task.rb +14 -4
  22. data/lib/pindo/module/task/model/build_task.rb +2 -0
  23. data/lib/pindo/module/task/model/git/git_commit_task.rb +11 -1
  24. data/lib/pindo/module/task/model/git/git_tag_task.rb +92 -77
  25. data/lib/pindo/module/task/model/jps/jps_workflow_message_task.rb +8 -10
  26. data/lib/pindo/module/task/model/unity/unity_export_task.rb +44 -0
  27. data/lib/pindo/module/task/pindo_task.rb +2 -2
  28. data/lib/pindo/module/task/task_manager.rb +14 -6
  29. data/lib/pindo/module/task/task_reporter.rb +45 -0
  30. data/lib/pindo/module/unity/nuget_helper.rb +5 -20
  31. data/lib/pindo/module/utils/git_repo_helper.rb +69 -36
  32. data/lib/pindo/module/xcode/ipa_resign_helper.rb +33 -62
  33. data/lib/pindo/module/xcode/res/xcode_res_handler.rb +25 -4
  34. data/lib/pindo/module/xcode/xcode_build_config.rb +7 -1
  35. data/lib/pindo/module/xcode/xcode_build_helper.rb +36 -4
  36. data/lib/pindo/module/xcode/xcode_res_helper.rb +8 -0
  37. data/lib/pindo/options/helpers/bundleid_selector.rb +23 -6
  38. data/lib/pindo/version.rb +1 -1
  39. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c4f5555594146ac02e8057cc535c1233b2c81b5204e6807a021744e9eeafd8b
4
- data.tar.gz: 1ad745131de6737f27c1c419253bf4dabc2c704cb2440f70ca7ad660d902b989
3
+ metadata.gz: db02bf00df627b07423ebd53475c538b60a4d5d8d567b2bb81a61390aaae73bc
4
+ data.tar.gz: 5252fb968e7bde86a095a78dce92599c9614061c1da9666e8cf2bea03927c8c6
5
5
  SHA512:
6
- metadata.gz: 0c505ba3e2a3f0c7bb74e6f57e588eeca6ab50844104abb98c4f02e6e676e584069135841f0793c951a0cc47c218e0d4b791c116ac5bffb7cc76437df9947218
7
- data.tar.gz: f0635784ade7e61a8b623238da8d60b04d221ceafb5312fea289063a065596db37aba8e6a67fe0210b4ece19e98d713d22fffd202805b4c530002f395265011c
6
+ metadata.gz: fa95f45065b4a8635c4d12c5a4c1d3a95e678df97724103857e055d9088d8f8613fddef8786229163bbd8ad01c87242e396e5b79e1c5f4d92411b61192e3bde1
7
+ data.tar.gz: 931bd858133452f7cc5a3edafc60cbe7c4f56b5d0f8da6d720f24c23f7974cfe2c823e0bbc7e1d1a04bc8f99faa581ef7c52ae99b0676ec6cfc4e407411e3e05
@@ -86,8 +86,7 @@ module Pindo
86
86
  end
87
87
 
88
88
  def add_branch(local_repo_dir: nil, branch: nil)
89
-
90
- current=Dir.pwd
89
+ # 命令已带 -C,无需 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
91
90
  result = false
92
91
 
93
92
  if !local_branch_exists?(local_repo_dir: local_repo_dir, branch: branch)
@@ -97,13 +96,11 @@ module Pindo
97
96
 
98
97
  git_remote!(local_repo_dir, %W(-C #{local_repo_dir} push origin #{branch}:#{branch}))
99
98
 
100
- Dir.chdir(current)
101
99
  return result
102
100
  end
103
101
 
104
102
  def remove_branch(local_repo_dir: nil, branch: nil)
105
- current=Dir.pwd
106
-
103
+ # 命令已带 -C,无需 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
107
104
  result = false
108
105
  if File.exist?(local_repo_dir)
109
106
  current_branch = git!(%W(-C #{local_repo_dir} rev-parse --abbrev-ref HEAD)).strip
@@ -120,51 +117,40 @@ module Pindo
120
117
  else
121
118
  result = false
122
119
  end
123
- Dir.chdir(current)
124
120
  return result
125
121
  end
126
122
 
127
123
 
128
124
  def local_branch_exists?(local_repo_dir: nil, branch: nil)
129
- current=Dir.pwd
125
+ # 命令改带 -C,去掉 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
130
126
  result = false
131
127
 
132
128
  if File.exist?(local_repo_dir)
133
- Dir.chdir(local_repo_dir)
134
-
135
- res_data = Executable.capture_command('git', %W(rev-parse --verify #{branch}), :capture => :out)
136
- # puts "=====1"
137
- # puts res_data
138
- # res_data = git!(%W(-C #{local_repo_dir} --no-pager branch --list origin/#{branch} --no-color -r))
129
+ res_data = Executable.capture_command('git', %W(-C #{local_repo_dir} rev-parse --verify #{branch}), :capture => :out)
139
130
  result = !res_data.nil? && !res_data.empty?
140
131
  else
141
132
  result = false
142
133
  end
143
- Dir.chdir(current)
144
134
  return result
145
135
  end
146
136
 
147
137
  def remote_branch_exists?(local_repo_dir: nil, branch: nil)
148
- current=Dir.pwd
138
+ # 命令已带 -C,无需 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
149
139
  result = false
150
140
  if File.exist?(local_repo_dir)
151
- Dir.chdir(local_repo_dir)
152
141
  res_data = git_remote!(local_repo_dir, %W(-C #{local_repo_dir} ls-remote --heads origin refs/heads/#{branch}))
153
142
  result = !res_data.nil? && !res_data.empty?
154
143
  else
155
144
  result = false
156
145
  end
157
- Dir.chdir(current)
158
146
  return result
159
147
  end
160
148
 
161
149
 
162
150
  def add_tag(local_repo_dir: nil, tag_name: nil)
163
-
164
- current=Dir.pwd
151
+ # 命令已带 -C,无需 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
165
152
  result = false
166
153
  if File.exist?(local_repo_dir)
167
- Dir.chdir(local_repo_dir)
168
154
  if !local_tag_exists?(local_repo_dir: local_repo_dir, tag_name: tag_name)
169
155
  git!(%W(-C #{local_repo_dir} tag #{tag_name}))
170
156
  result = true
@@ -173,7 +159,6 @@ module Pindo
173
159
  else
174
160
  result = false
175
161
  end
176
- Dir.chdir(current)
177
162
  return result
178
163
  end
179
164
 
@@ -207,11 +192,9 @@ module Pindo
207
192
  end
208
193
 
209
194
  def remove_tag(local_repo_dir: nil, tag_name: nil)
210
-
195
+ # 命令已带 -C,无需 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
211
196
  result = false
212
- current=Dir.pwd
213
197
  if File.exist?(local_repo_dir)
214
- Dir.chdir(local_repo_dir)
215
198
  if local_tag_exists?(local_repo_dir: local_repo_dir, tag_name: tag_name)
216
199
  git!(%W(-C #{local_repo_dir} tag -d #{tag_name}))
217
200
  result = true
@@ -223,51 +206,36 @@ module Pindo
223
206
  else
224
207
  result = false
225
208
  end
226
- Dir.chdir(current)
227
209
  return result
228
210
 
229
211
  end
230
212
 
231
213
 
232
- def remote_tag_exists?(local_repo_dir: nil, tag_name: nil)
233
-
234
- result = false
235
- current=Dir.pwd
236
-
237
- if File.exist?(local_repo_dir)
238
- Dir.chdir(local_repo_dir)
239
- tag_ref = "refs/tags/#{tag_name}"
240
- res_data = git_remote!(local_repo_dir, %W(-C #{local_repo_dir} ls-remote --tags origin #{tag_ref}))
241
- result = !res_data.nil? && !res_data.empty?
242
- else
243
- result = false
244
- end
245
- Dir.chdir(current)
246
- return result
247
-
214
+ # 获取远程 tag 指向的 commit SHA,不存在返回 nil
215
+ # 命令已带 -C,无需 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
216
+ def remote_tag_commit(local_repo_dir: nil, tag_name: nil)
217
+ return nil if local_repo_dir.nil? || !File.exist?(local_repo_dir)
218
+ tag_ref = "refs/tags/#{tag_name}"
219
+ res_data = git_remote!(local_repo_dir, %W(-C #{local_repo_dir} ls-remote --tags origin #{tag_ref}))
220
+ lines = res_data.to_s.lines.map(&:strip).reject(&:empty?)
221
+ return nil if lines.empty?
222
+ # annotated tag ^{} 解引用行才是真实 commit,优先取它
223
+ deref = lines.find { |l| l.include?("^{}") }
224
+ (deref || lines.first).split(/\s+/).first
225
+ end
248
226
 
227
+ def remote_tag_exists?(local_repo_dir: nil, tag_name: nil)
228
+ !remote_tag_commit(local_repo_dir: local_repo_dir, tag_name: tag_name).nil?
249
229
  end
250
230
 
251
231
  def local_tag_exists?(local_repo_dir: nil, tag_name: nil)
252
- # tag_ref = "refs/tags/#{tag_name}"
253
- result = false
254
- current=Dir.pwd
255
-
256
- if File.exist? (local_repo_dir)
257
- Dir.chdir(local_repo_dir)
258
- res_data = git!(%W(-C #{local_repo_dir} tag --list #{tag_name}))
259
- result = !res_data.nil? && !res_data.empty?
260
- else
261
- result = false
262
- end
263
- Dir.chdir(current)
264
- return result
232
+ return false if local_repo_dir.nil? || !File.exist?(local_repo_dir)
233
+ res_data = git!(%W(-C #{local_repo_dir} tag --list #{tag_name}))
234
+ !res_data.nil? && !res_data.empty?
265
235
  end
266
236
 
267
237
  def git_latest_commit_id(local_repo_dir:nil)
268
-
269
- current=Dir.pwd
270
-
238
+ # 命令已带 -C,无需 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
271
239
  unless File.exist?(File::join(local_repo_dir, ".git"))
272
240
  return nil
273
241
  end
@@ -275,16 +243,9 @@ module Pindo
275
243
  commit_id = nil
276
244
 
277
245
  if File.exist?(local_repo_dir)
278
- Dir.chdir(local_repo_dir)
279
246
  current_branch = git!(%W(-C #{local_repo_dir} rev-parse --abbrev-ref HEAD)).strip
280
- # puts "current_branch: #{current_branch}"
281
-
282
- # git log -n 1 --pretty=format:"commit %H"
283
- # format_str = "commit %H"
284
- # latest_log_info = git!(%W(-C #{current} log -n 1 --pretty=#{format_str} #{current_branch})).strip
285
247
  commit_id = git!(%W(-C #{local_repo_dir} rev-parse #{current_branch})).strip
286
248
  end
287
- Dir.chdir(current)
288
249
 
289
250
  return commit_id
290
251
  end
@@ -374,9 +335,11 @@ module Pindo
374
335
  rescue StandardError => e
375
336
  Funlog.instance.fancyinfo_error("仓库#{local_repo_dir}更新失败!")
376
337
  raise Informative, e.to_s
338
+ ensure
339
+ # 无论成功失败都还原 cwd,避免异常路径下污染全局工作目录
340
+ Dir.chdir(current)
377
341
  end
378
342
 
379
- Dir.chdir(current)
380
343
  return local_repo_dir
381
344
  end
382
345
 
@@ -476,12 +439,8 @@ module Pindo
476
439
  end
477
440
 
478
441
  def git_addpush_repo(path:nil, message:"res", commit_file_params:nil)
479
- current=Dir.pwd
480
- Dir.chdir(path)
481
-
482
- # gitee.com 仓库自动去除代理
442
+ # gitee.com 仓库自动去除代理;is_gitee_repo? 命令已带 -C,无需 chdir
483
443
  if is_gitee_repo?(local_repo_dir: path)
484
- Dir.chdir(current)
485
444
  return without_proxy { git_addpush_repo_impl(path: path, message: message, commit_file_params: commit_file_params) }
486
445
  end
487
446
 
@@ -524,10 +483,10 @@ module Pindo
524
483
  rescue => error
525
484
  # puts(error.to_s)
526
485
  raise Informative, "\n#{path}\n 仓库失败 !!!"
486
+ ensure
487
+ # 无论成功失败都还原 cwd,避免异常路径下污染全局工作目录
488
+ Dir.chdir(current)
527
489
  end
528
-
529
-
530
- Dir.chdir(current)
531
490
  end
532
491
 
533
492
 
@@ -560,8 +519,11 @@ module Pindo
560
519
  return nil
561
520
  end
562
521
 
563
- # 将字符串转换为数组
564
- files_list.is_a?(String) ? files_list.split("\n").reject(&:empty?) : files_list
522
+ # git!/IO#readpartial 返回的是 ASCII-8BIT 字符串,含非 ASCII 字节(如中文路径、
523
+ # core.quotePath=false 时的原始多字节)会与下游 UTF-8 字面量拼接失败,这里统一
524
+ # 标成 UTF-8 并 scrub 无效字节,避免上层 `puts "...#{file}"` 抛 Encoding::CompatibilityError
525
+ raw_list = files_list.is_a?(String) ? files_list.split("\n") : Array(files_list)
526
+ raw_list.map { |f| f.dup.force_encoding('UTF-8').scrub }.reject(&:empty?)
565
527
  rescue => e
566
528
  Funlog.instance.fancyinfo_error("获取未提交文件列表失败: #{e.message}")
567
529
  nil
@@ -636,14 +598,13 @@ module Pindo
636
598
  puts
637
599
 
638
600
  # 将文件列表分行并用红色显示
639
- if files.is_a?(String)
640
- files.split("\n").each do |file|
641
- puts " • #{file}".red unless file.empty?
642
- end
643
- else
644
- files.each do |file|
645
- puts " • #{file}".red unless file.empty?
646
- end
601
+ # 防御性编码归一化:git! 返回的是 ASCII-8BIT,与 UTF-8 字面量 " • " 拼接会抛
602
+ # Encoding::CompatibilityError;此处再兜一层,避免其它调用方传入 BINARY 字符串时崩溃
603
+ file_lines = files.is_a?(String) ? files.split("\n") : Array(files)
604
+ file_lines.each do |file|
605
+ next if file.nil? || file.empty?
606
+ safe_file = file.dup.force_encoding('UTF-8').scrub
607
+ puts " • #{safe_file}".red
647
608
  end
648
609
 
649
610
  puts
@@ -7,6 +7,7 @@ require 'pindo/module/build/build_helper'
7
7
  require 'pindo/module/utils/git_repo_helper'
8
8
  require 'pindo/module/xcode/xcode_build_config'
9
9
  require 'pindo/module/xcode/xcode_build_helper'
10
+ require 'pindo/base/git_handler'
10
11
  require 'pindo/config/ios_config_parser'
11
12
  require 'pindo/config/build_info_manager'
12
13
  require 'pindo/module/task/task_manager'
@@ -132,6 +133,10 @@ module Pindo
132
133
  pindo_project_dir = Dir.pwd
133
134
 
134
135
  begin
136
+ # 克隆公共/环境配置仓库(AdHoc 合并依赖 deploy_build_setting.json)
137
+ Pindo::GitHandler.clone_pindo_common_config_repo(force_delete: false)
138
+ Pindo::GitHandler.clone_pindo_env_config_repo(force_delete: false)
139
+
135
140
  # 加载 JPS 配置(如果存在)
136
141
  Pindo::BuildHelper.share_instance.load_jps_build_config(pindo_project_dir, conf: @args_conf)
137
142
 
@@ -196,6 +201,11 @@ module Pindo
196
201
  " 方式2: pindo appstore adhocbuild --bundleid=com.example.app"
197
202
  end
198
203
  end
204
+
205
+ # 在导出前合并 AdHoc 配置,确保 Unity AppConfig 等使用 AdHoc 值
206
+ # 失败 fail-fast:合并失败会抛 Informative 直接中断,
207
+ # 避免用原始 Bundle ID / Apple ID 产出错误身份的 AdHoc 包
208
+ Pindo::BuildInfoManager.share_instance.merge_adhoc_config_into_parser
199
209
  end
200
210
 
201
211
  # 创建构建任务
@@ -226,7 +236,7 @@ module Pindo
226
236
  # 1.1 Unity 配置编译模式任务(可选)
227
237
  unless @args_skip_config
228
238
  unity_config_task = Pindo::TaskSystem::UnityConfigTask.new(
229
- 'release', # AdHoc 也使用 release 模式
239
+ 'adhoc', # AdHoc 使用 adhoc 模式
230
240
  project_path: config[:project_path]
231
241
  )
232
242
  tasks << unity_config_task
@@ -263,7 +273,8 @@ module Pindo
263
273
  project_path: config[:project_path],
264
274
  export_path: ios_export_path,
265
275
  deploy_mode: 'adhoc', # AdHoc 使用 adhoc 模式
266
- context: unity_context
276
+ context: unity_context,
277
+ app_config: Pindo::IosConfigParser.instance.unity_appconfig_values # 导出前改写工程 AppConfig
267
278
  )
268
279
  unity_export_task.dependencies << last_task.id if last_task
269
280
  tasks << unity_export_task
@@ -253,7 +253,8 @@ module Pindo
253
253
  'ios',
254
254
  project_path: project_path,
255
255
  export_path: ios_export_path,
256
- deploy_mode: 'release' # AppStore 使用 release 模式
256
+ deploy_mode: 'release', # AppStore 使用 release 模式
257
+ app_config: Pindo::IosConfigParser.instance.unity_appconfig_values # 导出前改写工程 AppConfig
257
258
  )
258
259
  unity_export_task.dependencies << last_task.id
259
260
  tasks << unity_export_task
@@ -42,6 +42,28 @@ module Pindo
42
42
  def validate!
43
43
  super
44
44
 
45
+ # 加载配置
46
+ project_dir = Dir.pwd
47
+ config_file = File.join(project_dir, "config.json")
48
+
49
+ config_parser = Pindo::IosConfigParser.instance
50
+ config_parser.load_config(config_file: config_file)
51
+ @config_json = config_parser.config_json
52
+ @bundle_id = config_parser.bundle_id
53
+ @apple_id = config_parser.apple_id
54
+
55
+ if @config_json.nil? || @config_json.empty?
56
+ raise Informative, "配置未加载,请检查配置文件: #{config_file}"
57
+ end
58
+
59
+ if @bundle_id.nil? || @bundle_id.empty?
60
+ raise Informative, "无法从配置文件中获取 Bundle ID"
61
+ end
62
+
63
+ if @apple_id.nil? || @apple_id.empty?
64
+ raise Informative, "无法从配置文件中获取 Apple ID"
65
+ end
66
+
45
67
  pindo_dir = File.expand_path(pindo_single_config.pindo_dir)
46
68
  config_repo_dir = File.join(pindo_dir, @bundle_id)
47
69
  @iapconfig_dir = File.join(config_repo_dir, "fastlane/iap")
@@ -63,29 +85,6 @@ module Pindo
63
85
 
64
86
  def run
65
87
 
66
-
67
- # 加载配置
68
- project_dir = Dir.pwd
69
- config_file = File.join(project_dir, "config.json")
70
-
71
- config_parser = Pindo::IosConfigParser.instance
72
- config_parser.load_config(config_file: config_file)
73
- @config_json = config_parser.config_json
74
- @bundle_id = config_parser.bundle_id
75
- @apple_id = config_parser.apple_id
76
-
77
- if @config_json.nil? || @config_json.empty?
78
- raise Informative, "配置未加载,请检查配置文件: #{config_file}"
79
- end
80
-
81
- if @bundle_id.nil? || @bundle_id.empty?
82
- raise Informative, "无法从配置文件中获取 Bundle ID"
83
- end
84
-
85
- if @apple_id.nil? || @apple_id.empty?
86
- raise Informative, "无法从配置文件中获取 Apple ID"
87
- end
88
-
89
88
  if @download_flag
90
89
 
91
90
  login_api_key(apple_id: @apple_id)
@@ -121,18 +120,7 @@ module Pindo
121
120
  def download_appstore_iap(appstore_iap_file: nil)
122
121
  puts "正在下载appstore iap 信息 ..."
123
122
 
124
- app_list_response = @app_store_connect.list_apps(filter: {
125
- bundle_id: @bundle_id
126
- })
127
-
128
- current_app = nil
129
- app_list_response[:data].each do |app_info|
130
- if app_info[:attributes][:bundle_id].to_s.eql?(@bundle_id)
131
- current_app = app_info
132
- end
133
- end
134
-
135
- app_id = current_app[:id]
123
+ app_id = find_appstore_app_id
136
124
 
137
125
  puts " "
138
126
  puts "app_id : #{app_id} +++++++++"
@@ -162,7 +150,7 @@ module Pindo
162
150
 
163
151
  pindo_dir = File.expand_path(pindo_single_config.pindo_dir)
164
152
  config_repo_dir = File.join(pindo_dir, @bundle_id)
165
- git_addpush_repo(path: config_repo_dir, message: "download app iap", commit_file_params: ["fastlane/iap/iap_appstore_download.json"])
153
+ Pindo::GitHandler.git_addpush_repo(path: config_repo_dir, message: "download app iap", commit_file_params: ["fastlane/iap/iap_appstore_download.json"])
166
154
 
167
155
  update_app_share_secrets(app_id: app_id, need_create: false)
168
156
  end
@@ -307,39 +295,51 @@ module Pindo
307
295
  file.close
308
296
  end
309
297
 
310
- git_addpush_repo(path: config_repo_dir, message: "update app shared secret", commit_file_params: ["config.json"])
298
+ Pindo::GitHandler.git_addpush_repo(path: config_repo_dir, message: "update app shared secret", commit_file_params: ["config.json"])
311
299
 
312
300
  end
313
301
 
314
302
 
315
303
  end
316
304
 
317
- def create_appstore_iap(appstore_iap_file: nil)
305
+ def find_appstore_app_id
318
306
 
319
- temp_iap_json = JSON.parse(File.read(appstore_iap_file))
307
+ app_list_response = @app_store_connect.list_apps(filter: {
308
+ bundle_id: @bundle_id
309
+ })
320
310
 
321
- if @check_flag
322
- check_purchase_items_right(in_app_purchase_json: temp_iap_json, config_json: @config_json)
311
+ if app_list_response.nil? || app_list_response[:data].nil?
312
+ error_detail = if !app_list_response.nil? && !app_list_response[:errors].nil?
313
+ JSON.pretty_generate(app_list_response[:errors])
314
+ else
315
+ app_list_response.inspect
316
+ end
317
+ raise Informative, "获取 App 列表失败,App Store Connect 返回:\n#{error_detail}"
323
318
  end
324
319
 
325
- in_app_purchase_json = process_purchase_items(in_app_purchase_json: temp_iap_json, iap_tester: @iaptester)
320
+ current_app = app_list_response[:data].find do |app_info|
321
+ app_info[:attributes][:bundle_id].to_s.eql?(@bundle_id)
322
+ end
326
323
 
324
+ if current_app.nil?
325
+ raise Informative, "在 App Store Connect 中未找到 Bundle ID 为 #{@bundle_id} 的 App"
326
+ end
327
327
 
328
- app_list_response = @app_store_connect.list_apps(filter: {
329
- bundle_id: @bundle_id
330
- })
328
+ current_app[:id]
329
+ end
331
330
 
331
+ def create_appstore_iap(appstore_iap_file: nil)
332
332
 
333
- # puts app_list_response
334
- current_app = nil
333
+ temp_iap_json = JSON.parse(File.read(appstore_iap_file))
335
334
 
336
- app_list_response[:data].each do |app_info|
337
- if app_info[:attributes][:bundle_id].to_s.eql?(@bundle_id)
338
- current_app = app_info
339
- end
335
+ if @check_flag
336
+ check_purchase_items_right(in_app_purchase_json: temp_iap_json, config_json: @config_json)
340
337
  end
341
338
 
342
- app_id = current_app[:id]
339
+ in_app_purchase_json = process_purchase_items(in_app_purchase_json: temp_iap_json, iap_tester: @iaptester)
340
+
341
+
342
+ app_id = find_appstore_app_id
343
343
 
344
344
  puts " "
345
345
  puts "app_id : #{app_id} +++++++++"
@@ -789,7 +789,11 @@ module Pindo
789
789
  @iaptester = sandbox_tester_json["iaptester"]
790
790
  end
791
791
 
792
- if !@iaptester.nil? && @iaptester["need_create"]
792
+ if @iaptester.nil?
793
+ raise Informative, "没有Sandbox Tester !!!"
794
+ end
795
+
796
+ if @iaptester["need_create"]
793
797
  puts
794
798
  puts
795
799
  if itc_has_sandbox_tester(email: @iaptester["email"])
@@ -806,7 +810,7 @@ module Pindo
806
810
  end
807
811
  end
808
812
  else
809
- raise Informative, "没有Sandbox Tester !!!"
813
+ puts "沙盒账号:#{@iaptester["email"]} 配置 need_create=false,跳过创建。"
810
814
  end
811
815
 
812
816
  end
@@ -43,7 +43,7 @@ module Pindo
43
43
  def initialize(argv)
44
44
 
45
45
  @args_repo_name = argv.shift_argument
46
- @args_login_flag = argv.flag?('force', false)
46
+ @args_login_flag = argv.flag?('login', false)
47
47
  @repo_name = argv.option('repo')
48
48
  @org_name = argv.option('org')
49
49
 
@@ -48,7 +48,7 @@ module Pindo
48
48
  def initialize(argv)
49
49
 
50
50
  @args_repo_name = argv.shift_argument
51
- @args_login_flag = argv.flag?('force', false)
51
+ @args_login_flag = argv.flag?('login', false)
52
52
  @repo_name = argv.option('repo')
53
53
  @org_name = argv.option('org')
54
54
 
@@ -159,8 +159,8 @@ module Pindo
159
159
  Funlog.fancyinfo_start("克隆仓库: #{url}...")
160
160
  Funlog.info("仓库 URL: #{url}") if ENV['PINDO_DEBUG']
161
161
 
162
- # 克隆仓库
163
- success = system("git clone #{url} #{temp_dir} --quiet 2>/dev/null")
162
+ # 克隆仓库(数组参数形式,避免 URL 中的 shell 元字符注入)
163
+ success = system("git", "clone", url, temp_dir, "--quiet", err: File::NULL)
164
164
 
165
165
  unless success && File.exist?(File.join(temp_dir, '.git'))
166
166
  Funlog.fancyinfo_error("仓库克隆失败: #{url}")
@@ -142,7 +142,6 @@ module Pindo
142
142
  new_project_dir = File.join(File::expand_path(current_dir + "/../") , temp_dir_name)
143
143
 
144
144
  if File.exist?(new_project_dir)
145
- system 'sh rm -rf ' + new_project_dir
146
145
  FileUtils.rm_rf(new_project_dir)
147
146
  end
148
147
  FileUtils.mkdir(new_project_dir)
@@ -2,6 +2,7 @@ require 'singleton'
2
2
  require 'fileutils'
3
3
  require 'pindo/base/git_handler'
4
4
  require 'pindo/config/pindoconfig'
5
+ require 'pindo/config/ios_config_parser'
5
6
 
6
7
  module Pindo
7
8
 
@@ -174,6 +175,36 @@ module Pindo
174
175
  end
175
176
  end
176
177
 
178
+ # 解析并克隆 AdHoc 配置仓库,将 AdHoc 配置合并进 IosConfigParser 单例
179
+ # 供命令层(导出前)与 AdHoc 构建任务复用;幂等,可重复调用
180
+ # @return [String, nil] AdHoc 配置仓库目录;无 app_type 时返回 nil
181
+ def merge_adhoc_config_into_parser
182
+ config_parser = Pindo::IosConfigParser.instance
183
+
184
+ # 幂等短路:已合并则直接复用缓存目录,避免重复克隆与重复改写
185
+ return config_parser.adhoc_config_dir if config_parser.adhoc_merged?
186
+
187
+ config_json = config_parser.config_json
188
+ unless config_json && config_json.dig('project_info', 'app_type')
189
+ puts "配置中缺少 app_type,跳过 AdHoc 配置合并"
190
+ return nil
191
+ end
192
+
193
+ adhoc_repo_name = get_deploy_repo_with_modul_name(
194
+ module_name: config_json['project_info']['app_type']
195
+ )
196
+ if adhoc_repo_name.nil? || adhoc_repo_name.empty?
197
+ raise Informative, "config.json app_type is error!!!"
198
+ end
199
+
200
+ adhoc_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: adhoc_repo_name)
201
+
202
+ # 合并失败采用 fail-fast:modify_config_with_adhoc 会抛 Informative,
203
+ # 直接冒泡给调用方,避免静默退化为原始配置产出错误身份的包
204
+ config_parser.modify_config_with_adhoc(adhoc_config_dir: adhoc_config_dir)
205
+ adhoc_config_dir
206
+ end
207
+
177
208
  # 将仓库注册到 git_base_url.json,指定其所属 org
178
209
  def modify_repo_setting(repo_name:, owner_org:)
179
210
  pindo_setting_dir = pindo_single_config.pindo_env_configdir