pindo 5.18.13 → 5.18.20

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.
@@ -98,6 +98,16 @@ module Pindo
98
98
  if enable_pad
99
99
  pad_backup!(context)
100
100
  run_pad!(context)
101
+
102
+ # 临时 PAD 默认会在 cleanup! 中恢复备份并删除 created_dirs(即 *_pack),以实现回滚。
103
+ # 但某些工程会在构建结束后用“基线文件/外部备份”覆盖当前 build.gradle,
104
+ # 若该基线不包含 assetPacks/include,会导致引用丢失。
105
+ #
106
+ # 当显式开启 PINDO_PAD_KEEP_REFS=1 时:
107
+ # - 将 PAD 写入后的 settings.gradle / launcher/build.gradle 同步进备份快照,
108
+ # 以确保 cleanup! 恢复后仍保留 assetPacks/include;
109
+ # - 同时 cleanup! 将跳过删除 created_dirs,保留 *_pack 目录,保持工程可 sync。
110
+ sync_pad_refs_to_backups!(context) if pad_keep_refs_enabled?
101
111
  end
102
112
 
103
113
  # 2) 注入 buildType/signingConfig(对所有 Android modules)
@@ -242,15 +252,26 @@ module Pindo
242
252
  backups.each do |item|
243
253
  path = File.join(project_dir, item.fetch("path"))
244
254
  backup_path = File.join(project_dir, item.fetch("backup_path"))
245
- next unless File.file?(backup_path)
246
255
 
247
- FileUtils.mkdir_p(File.dirname(path))
248
- bin_copy(backup_path, path)
256
+ if item["type"] == "dir"
257
+ next unless File.directory?(backup_path)
258
+ FileUtils.rm_rf(path) if File.exist?(path)
259
+ FileUtils.mkdir_p(File.dirname(path))
260
+ FileUtils.cp_r(backup_path, path)
261
+ else
262
+ next unless File.file?(backup_path)
263
+ FileUtils.mkdir_p(File.dirname(path))
264
+ bin_copy(backup_path, path)
265
+ end
249
266
  end
250
267
 
251
- (data["created_dirs"] || []).each do |rel|
252
- abs = File.join(project_dir, rel)
253
- FileUtils.rm_rf(abs) if abs.start_with?(project_dir.to_s)
268
+ # 临时 PAD 默认会清理 created_dirs(通常是 *_pack)。
269
+ # 若显式开启 PINDO_PAD_KEEP_REFS=1,则保留 pack 目录与引用,避免构建结束后被外部基线覆盖而丢引用。
270
+ unless ENV.fetch("PINDO_PAD_KEEP_REFS", "").to_s.strip.downcase.match?(/\A(1|true|yes|on)\z/)
271
+ (data["created_dirs"] || []).each do |rel|
272
+ abs = File.join(project_dir, rel)
273
+ FileUtils.rm_rf(abs) if abs.start_with?(project_dir.to_s)
274
+ end
254
275
  end
255
276
  end
256
277
 
@@ -529,7 +550,6 @@ module Pindo
529
550
  def groovy_signing_config_entry(workflow_name:, workflow_build_type:, signing_config_name:)
530
551
  lines = []
531
552
  lines << "// #{MARK_BEGIN}"
532
- lines << "// workflowName=#{workflow_name.inspect}"
533
553
  lines << "#{signing_config_name} {"
534
554
  lines << " def signingEnvVars = #{RELEASE_SIGNING_ENV_VARS.inspect}"
535
555
  lines << " def hasCompleteReleaseSigningEnv = signingEnvVars.every { System.getenv(it) }"
@@ -553,7 +573,6 @@ module Pindo
553
573
  def kts_signing_config_entry(workflow_name:, workflow_build_type:, signing_config_name:)
554
574
  lines = []
555
575
  lines << "// #{MARK_BEGIN}"
556
- lines << "// workflowName=#{workflow_name.inspect}"
557
576
  lines << "create(\"#{signing_config_name}\") {"
558
577
  lines << " val signingEnvVars = listOf("
559
578
  RELEASE_SIGNING_ENV_VARS.each_with_index do |v, idx|
@@ -582,7 +601,6 @@ module Pindo
582
601
  def groovy_build_type_entry(workflow_name:, workflow_build_type:, signing_config_name:, is_main_module:)
583
602
  lines = []
584
603
  lines << "// #{MARK_BEGIN}"
585
- lines << "// workflowName=#{workflow_name.inspect}"
586
604
  lines << "#{workflow_build_type} {"
587
605
  lines << " minifyEnabled false"
588
606
  if is_main_module
@@ -597,7 +615,6 @@ module Pindo
597
615
  def kts_build_type_entry(workflow_name:, workflow_build_type:, signing_config_name:, is_main_module:)
598
616
  lines = []
599
617
  lines << "// #{MARK_BEGIN}"
600
- lines << "// workflowName=#{workflow_name.inspect}"
601
618
  lines << "create(\"#{workflow_build_type}\") {"
602
619
  lines << " isMinifyEnabled = false"
603
620
  if is_main_module
@@ -743,7 +760,7 @@ module Pindo
743
760
  end.join
744
761
  end
745
762
 
746
- def backup_file!(context, abs_path)
763
+ def backup_file!(context, abs_path, force: false)
747
764
  project_dir = context[:project_dir]
748
765
  return unless abs_path && File.file?(abs_path)
749
766
  return unless abs_path.start_with?(project_dir.to_s)
@@ -751,7 +768,10 @@ module Pindo
751
768
  rel = abs_path.delete_prefix("#{project_dir}/")
752
769
 
753
770
  # 已备份过就跳过
754
- return if context[:backups].any? { |b| b["path"] == rel && b["type"] == "file" }
771
+ if (existing = context[:backups].find { |b| b["path"] == rel && b["type"] == "file" })
772
+ return unless force
773
+ context[:backups].delete(existing)
774
+ end
755
775
 
756
776
  backup_path = File.join(context[:backup_dir], rel)
757
777
  FileUtils.mkdir_p(File.dirname(backup_path))
@@ -765,6 +785,22 @@ module Pindo
765
785
  }
766
786
  end
767
787
 
788
+ def pad_keep_refs_enabled?
789
+ ENV.fetch("PINDO_PAD_KEEP_REFS", "").to_s.strip.downcase.match?(/\A(1|true|yes|on)\z/)
790
+ end
791
+
792
+ def sync_pad_refs_to_backups!(context)
793
+ project_dir = context[:project_dir]
794
+
795
+ settings = find_settings_gradle(project_dir)
796
+ backup_file!(context, settings, force: true) if settings
797
+
798
+ launcher_groovy = File.join(project_dir, "launcher", "build.gradle")
799
+ launcher_kts = File.join(project_dir, "launcher", "build.gradle.kts")
800
+ backup_file!(context, launcher_kts, force: true) if File.file?(launcher_kts)
801
+ backup_file!(context, launcher_groovy, force: true) if File.file?(launcher_groovy)
802
+ end
803
+
768
804
  def self.bin_copy(src, dst)
769
805
  File.open(src, "rb") do |r|
770
806
  File.open(dst, "wb") do |w|
@@ -186,9 +186,9 @@ module Pindo
186
186
  begin
187
187
  response = appstore_client.create_in_app_purchase(
188
188
  name:purchase_item["reference_name"],
189
- product_id:purchase_item["product_id"],
190
- in_app_purchase_type:purchase_item["in_app_purchase_type"],
191
- review_note:purchase_item["review_note"],
189
+ productId:purchase_item["product_id"],
190
+ inAppPurchaseType:purchase_item["in_app_purchase_type"],
191
+ reviewNote:purchase_item["review_note"],
192
192
  relationships: {
193
193
  app:{
194
194
  data:{
@@ -228,7 +228,7 @@ module Pindo
228
228
  begin
229
229
  response = appstore_client.update_in_app_purchase(
230
230
  name:purchase_item["reference_name"],
231
- review_note:purchase_item["review_note"],
231
+ reviewNote:purchase_item["review_note"],
232
232
  id:in_app_purchase_id
233
233
  )
234
234
  rescue => err
@@ -255,22 +255,34 @@ module Pindo
255
255
  end
256
256
  end
257
257
 
258
- response = appstore_client.modify_in_app_purchase_territory_availablity(
259
- available_in_new_territories:true,
260
- relationships: {
261
- inAppPurchase:{
262
- data:{
263
- id: in_app_purchase_id,
264
- type: 'inAppPurchases'
265
- }
266
- },
267
- availableTerritories:{
268
- data:availableTerritories_data
269
- }
258
+ body = {
259
+ data: {
260
+ type: "inAppPurchaseAvailabilities",
261
+ attributes: {
262
+ availableInNewTerritories: true
263
+ },
264
+ relationships: {
265
+ inAppPurchase: {
266
+ data: {
267
+ id: in_app_purchase_id,
268
+ type: 'inAppPurchases'
270
269
  }
271
- )
270
+ },
271
+ availableTerritories: {
272
+ data: availableTerritories_data
273
+ }
274
+ }
275
+ }
276
+ }
272
277
 
273
- # puts JSON.pretty_generate(response)
278
+ begin
279
+ client = Spaceship::ConnectAPI
280
+ client.tunes_request_client.post("#{Spaceship::ConnectAPI::Tunes::API::Version::V1}/inAppPurchaseAvailabilities", body)
281
+ puts " Territory Availability 设置成功"
282
+ rescue => err
283
+ puts err
284
+ puts " 设置Territory Availability失败!!!"
285
+ end
274
286
 
275
287
  end
276
288
 
@@ -396,7 +408,7 @@ module Pindo
396
408
  if !price_id.nil?
397
409
  purchase_response = appstore_client.create_in_app_purchase_price_schedule(
398
410
  relationships: {
399
- manual_prices: {
411
+ manualPrices: {
400
412
  data: [
401
413
  {
402
414
  type: 'inAppPurchasePrices',
@@ -404,7 +416,7 @@ module Pindo
404
416
  }
405
417
  ]
406
418
  },
407
- in_app_purchase: {
419
+ inAppPurchase: {
408
420
  data: {
409
421
  type: 'inAppPurchases',
410
422
  id: in_app_purchase_id
@@ -488,8 +500,8 @@ module Pindo
488
500
 
489
501
  puts " 正在上传...."
490
502
  response_iap_screenshot = appstore_client.create_in_app_purchase_review_screenshot(
491
- file_name:filename,
492
- file_size: filesize,
503
+ fileName:filename,
504
+ fileSize: filesize,
493
505
  relationships: {
494
506
  inAppPurchaseV2:{
495
507
  data:{
@@ -519,7 +531,7 @@ module Pindo
519
531
  in_app_purchase = appstore_client.update_in_app_purchase_app_store_review_screenshot(
520
532
  id:upload_id,
521
533
  uploaded: true,
522
- source_file_checksum:checksum
534
+ sourceFileChecksum:checksum
523
535
  )
524
536
  puts " 上传完成!!"
525
537
 
@@ -632,7 +644,7 @@ module Pindo
632
644
 
633
645
  begin
634
646
  group_response = appstore_client.create_subscription_group(
635
- reference_name:subscription_group_item["group_reference_name"],
647
+ referenceName:subscription_group_item["group_reference_name"],
636
648
  relationships: {
637
649
  app:{
638
650
  data:{
@@ -684,7 +696,7 @@ module Pindo
684
696
  response = appstore_client.update_subscription_group_localization(
685
697
  id:locale_item["locale_id"],
686
698
  name:locale_item["group_display_name"],
687
- custom_app_name:locale_item["custom_app_name"]
699
+ customAppName:locale_item["custom_app_name"]
688
700
  )
689
701
  # puts JSON.pretty_generate(response)
690
702
 
@@ -693,7 +705,7 @@ module Pindo
693
705
  response = appstore_client.create_subscription_group_localization(
694
706
  name:locale_item["group_display_name"],
695
707
  locale:locale,
696
- custom_app_name:locale_item["custom_app_name"],
708
+ customAppName:locale_item["custom_app_name"],
697
709
  relationships: {
698
710
  subscriptionGroup:{
699
711
  data:{
@@ -881,11 +893,11 @@ module Pindo
881
893
  begin
882
894
  response = appstore_client.create_subscription(
883
895
  name:subscription_item["reference_name"],
884
- product_id:subscription_item["product_id"],
885
- family_sharable:false,
886
- review_note:subscription_item["review_note"],
887
- subscription_period:subscription_item["subscription_duration"],
888
- group_level:1,
896
+ productId:subscription_item["product_id"],
897
+ familySharable:false,
898
+ reviewNote:subscription_item["review_note"],
899
+ subscriptionPeriod:subscription_item["subscription_duration"],
900
+ groupLevel:1,
889
901
  relationships: {
890
902
  group:{
891
903
  data:{
@@ -928,9 +940,9 @@ module Pindo
928
940
  response = appstore_client.update_subscription(
929
941
  id:subscription_id,
930
942
  name:subscription_item["reference_name"],
931
- family_sharable:false,
932
- review_note:subscription_item["review_note"],
933
- group_level:1
943
+ familySharable:false,
944
+ reviewNote:subscription_item["review_note"],
945
+ groupLevel:1
934
946
  )
935
947
  # puts JSON.pretty_generate(response)
936
948
 
@@ -962,7 +974,7 @@ module Pindo
962
974
  puts " 设置订阅的周期: #{subscription_item["subscription_duration"]}"
963
975
  response = appstore_client.update_subscription(
964
976
  id:subscription_id,
965
- subscription_period:subscription_item["subscription_duration"]
977
+ subscriptionPeriod:subscription_item["subscription_duration"]
966
978
  )
967
979
  # puts JSON.pretty_generate(response)
968
980
 
@@ -998,22 +1010,34 @@ module Pindo
998
1010
  availableTerritories_data << new_territory_item
999
1011
  end
1000
1012
  end
1001
- response = appstore_client.modify_subscription_territory_availability(
1002
- available_in_new_territories:true,
1003
- relationships: {
1004
- subscription:{
1005
- data:{
1006
- id: subscription_id,
1007
- type: 'subscriptions'
1008
- }
1009
- },
1010
- availableTerritories:{
1011
- data:availableTerritories_data
1012
- }
1013
+ body = {
1014
+ data: {
1015
+ type: "subscriptionAvailabilities",
1016
+ attributes: {
1017
+ availableInNewTerritories: true
1018
+ },
1019
+ relationships: {
1020
+ subscription: {
1021
+ data: {
1022
+ id: subscription_id,
1023
+ type: 'subscriptions'
1013
1024
  }
1014
- )
1025
+ },
1026
+ availableTerritories: {
1027
+ data: availableTerritories_data
1028
+ }
1029
+ }
1030
+ }
1031
+ }
1015
1032
 
1016
- # puts JSON.pretty_generate(response)
1033
+ begin
1034
+ client = Spaceship::ConnectAPI
1035
+ client.tunes_request_client.post("#{Spaceship::ConnectAPI::Tunes::API::Version::V1}/subscriptionAvailabilities", body)
1036
+ puts " Territory Availability 设置成功"
1037
+ rescue => err
1038
+ puts err
1039
+ puts " 设置订阅的Territory Availability失败!!!"
1040
+ end
1017
1041
  end
1018
1042
 
1019
1043
 
@@ -1624,8 +1648,8 @@ module Pindo
1624
1648
 
1625
1649
  response = appstore_client.create_subscription_introductory_offer(
1626
1650
  duration:"THREE_DAYS",
1627
- number_of_periods:1,
1628
- offer_mode:'FREE_TRIAL',
1651
+ numberOfPeriods:1,
1652
+ offerMode:'FREE_TRIAL',
1629
1653
  relationships: {
1630
1654
  subscription: {
1631
1655
  data: {
@@ -1688,7 +1712,7 @@ module Pindo
1688
1712
  if !price_point_id.nil?
1689
1713
 
1690
1714
  respose_price = appstore_client.create_subscription_price(
1691
- preserve_current_price:true,
1715
+ preserveCurrentPrice:true,
1692
1716
  relationships: {
1693
1717
  subscription: {
1694
1718
  data: {
@@ -1733,7 +1757,7 @@ module Pindo
1733
1757
  puts " " + index_item.to_s + ".更新价格 地区:" + territory_id+ " 价格:" + price_local_item[:attributes][:customer_price]
1734
1758
 
1735
1759
  respose_price = appstore_client.create_subscription_price(
1736
- preserve_current_price:true,
1760
+ preserveCurrentPrice:true,
1737
1761
  relationships: {
1738
1762
  subscription: {
1739
1763
  data: {
@@ -1814,8 +1838,8 @@ module Pindo
1814
1838
 
1815
1839
  puts " 正在上传...."
1816
1840
  response_iap_screenshot = appstore_client.create_subscription_review_screenshot(
1817
- file_name:filename,
1818
- file_size: filesize,
1841
+ fileName:filename,
1842
+ fileSize: filesize,
1819
1843
  relationships: {
1820
1844
  subscription:{
1821
1845
  data:{
@@ -1848,7 +1872,7 @@ module Pindo
1848
1872
  in_app_purchase = appstore_client.update_subscription_review_screenshot(
1849
1873
  id:upload_id,
1850
1874
  uploaded: true,
1851
- source_file_checksum:checksum
1875
+ sourceFileChecksum:checksum
1852
1876
  )
1853
1877
  puts " 上传完成!!"
1854
1878
  # puts JSON.pretty_generate(in_app_purchase)
@@ -50,36 +50,10 @@ module Pindo
50
50
  load_ios_config
51
51
 
52
52
  # 1.5 获取 AdHoc 配置目录并合并配置
53
- adhoc_config_dir = nil
54
- begin
55
- config_parser = Pindo::IosConfigParser.instance
56
- config_json = config_parser.config_json
57
-
58
- # 根据 app_type 获取 AdHoc 配置仓库
59
- if config_json && config_json['project_info'] && config_json['project_info']['app_type']
60
- require 'pindo/config/build_info_manager'
61
-
62
- build_info_manager = Pindo::BuildInfoManager.share_instance
63
- adhoc_repo_name = build_info_manager.get_deploy_repo_with_modul_name(
64
- module_name: config_json['project_info']['app_type']
65
- )
66
-
67
- if adhoc_repo_name.nil? || adhoc_repo_name.empty?
68
- raise Informative, "config.json app_type is error!!!"
69
- end
70
-
71
- # 克隆 AdHoc 配置仓库
72
- adhoc_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: adhoc_repo_name)
73
-
74
- # 合并 AdHoc 配置
75
- config_parser.modify_config_with_adhoc(adhoc_config_dir: adhoc_config_dir)
76
- else
77
- puts "配置中缺少 app_type,跳过 AdHoc 配置合并"
78
- end
79
- rescue => e
80
- puts "获取 AdHoc 配置失败: #{e.message}"
81
- adhoc_config_dir = nil
82
- end
53
+ # 复用 BuildInfoManager(命令层在导出前可能已合并过,幂等短路直接返回缓存目录)
54
+ # 合并失败 fail-fast:抛 Informative 由 TaskManager 标记任务失败
55
+ require 'pindo/config/build_info_manager'
56
+ adhoc_config_dir = Pindo::BuildInfoManager.share_instance.merge_adhoc_config_into_parser
83
57
 
84
58
  # 2. 自动增加版本号
85
59
  auto_increase_buildnumber
@@ -78,11 +78,21 @@ module Pindo
78
78
  latest_output = all_outputs.max_by { |f| File.mtime(f) }
79
79
  output_type = latest_output.end_with?('.ipa') ? 'IPA' : 'APP'
80
80
  puts " 找到 #{output_type} 文件: #{latest_output}"
81
- latest_output
82
- else
83
- puts " 警告: 未找到 IPA 或 APP 文件"
84
- nil
81
+ return latest_output
82
+ end
83
+
84
+ # 命令行工具产物为裸可执行文件(build 根目录下无扩展名的普通文件)
85
+ tool_outputs = Dir.glob(File.join(build_dir, "*")).select do |f|
86
+ File.file?(f) && File.extname(f).empty?
85
87
  end
88
+ if tool_outputs.any?
89
+ latest_output = tool_outputs.max_by { |f| File.mtime(f) }
90
+ puts " 找到命令行工具可执行文件: #{latest_output}"
91
+ return latest_output
92
+ end
93
+
94
+ puts " 警告: 未找到 IPA / APP / 可执行文件"
95
+ nil
86
96
  end
87
97
 
88
98
  # 处理 CocoaPods 依赖(Dev 构建)
@@ -107,8 +107,22 @@ module Pindo
107
107
  if @process_type == Pindo::UncommittedFilesProcessType::SKIP_WITHOUT_TAG
108
108
  coding_branch = get_current_branch_name
109
109
  @build_number, @commit_hash = git_repo_helper.get_build_number_from_commit(project_dir: root_dir)
110
- @build_version = "0.0.0"
110
+
111
+ # 版本号仍按正常优先级计算,仅"不打 tag / 不升版本",避免硬编码 0.0.0 污染 build.gradle 与下游上传参数
112
+ if @fixed_version && !@fixed_version.empty?
113
+ @build_version = @fixed_version
114
+ else
115
+ @build_version = git_repo_helper.calculate_build_version(
116
+ project_dir: root_dir,
117
+ tag_prefix: @tag_pre,
118
+ create_tag_type: Pindo::CreateTagType::NONE,
119
+ version_increase_type: @ver_inc
120
+ )
121
+ end
122
+
123
+ commit_short = @commit_hash ? @commit_hash[0..7] : "unknown"
111
124
  Funlog.instance.fancyinfo_warning("skip_without_tag 模式:跳过分支合并和 tag 创建")
125
+ Funlog.instance.fancyinfo_success("Version: #{@build_version}, Build: #{@build_number}, Commit: #{commit_short}")
112
126
 
113
127
  # 显示 commit 信息后直接返回
114
128
  display_all_repos_commit_info(root_dir)