pindo 5.17.4 → 5.18.3

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 (55) 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 +92 -31
  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/unity/autobuild.rb +38 -18
  12. data/lib/pindo/command/utils/allcopyconfig.rb +144 -0
  13. data/lib/pindo/command/utils/copyconfig.rb +207 -0
  14. data/lib/pindo/command/utils/icon.rb +2 -2
  15. data/lib/pindo/command/utils/renewbundleid.rb +199 -0
  16. data/lib/pindo/command/utils/renewcert.rb +56 -54
  17. data/lib/pindo/command/utils.rb +3 -0
  18. data/lib/pindo/command/web/autobuild.rb +10 -8
  19. data/lib/pindo/config/build_info_manager.rb +1 -3
  20. data/lib/pindo/module/android/android_build_helper.rb +198 -33
  21. data/lib/pindo/module/android/android_config_helper.rb +305 -88
  22. data/lib/pindo/module/android/android_project_helper.rb +124 -14
  23. data/lib/pindo/module/android/android_res_helper.rb +349 -51
  24. data/lib/pindo/module/android/keystore_helper.rb +611 -295
  25. data/lib/pindo/module/android/workflow_gradle_injector.rb +702 -0
  26. data/lib/pindo/module/appselect.rb +4 -4
  27. data/lib/pindo/module/appstore/bundleid_helper.rb +204 -14
  28. data/lib/pindo/module/build/build_helper.rb +76 -10
  29. data/lib/pindo/module/build/git_repo_helper.rb +4 -4
  30. data/lib/pindo/module/cert/mode/base_cert_operator.rb +12 -6
  31. data/lib/pindo/module/pgyer/pgyerhelper.rb +124 -39
  32. data/lib/pindo/module/task/model/build/android_build_dev_task.rb +64 -6
  33. data/lib/pindo/module/task/model/git/git_commit_task.rb +70 -54
  34. data/lib/pindo/module/task/model/git/git_tag_task.rb +13 -9
  35. data/lib/pindo/module/task/model/jps/jps_upload_task.rb +110 -3
  36. data/lib/pindo/module/task/model/unity/unity_export_task.rb +2 -1
  37. data/lib/pindo/module/task/model/unity/unity_update_task.rb +2 -1
  38. data/lib/pindo/module/task/model/unity/unity_yoo_asset_task.rb +2 -1
  39. data/lib/pindo/module/task/model/unity_task.rb +2 -1
  40. data/lib/pindo/module/unity/unity_helper.rb +13 -10
  41. data/lib/pindo/module/unity/unity_proc_helper.rb +27 -2
  42. data/lib/pindo/module/xcode/applovin_xcode_helper.rb +6 -2
  43. data/lib/pindo/module/xcode/res/xcode_res_constant.rb +72 -0
  44. data/lib/pindo/module/xcode/res/xcode_res_handler.rb +3 -3
  45. data/lib/pindo/module/xcode/xcode_build_config.rb +46 -17
  46. data/lib/pindo/module/xcode/xcode_build_helper.rb +186 -25
  47. data/lib/pindo/module/xcode/xcode_project_helper.rb +1 -1
  48. data/lib/pindo/module/xcode/xcode_res_helper.rb +32 -16
  49. data/lib/pindo/options/groups/build_options.rb +5 -5
  50. data/lib/pindo/options/groups/git_options.rb +7 -5
  51. data/lib/pindo/options/groups/unity_options.rb +11 -0
  52. data/lib/pindo/options/helpers/bundleid_selector.rb +25 -0
  53. data/lib/pindo/options/helpers/git_constants.rb +7 -6
  54. data/lib/pindo/version.rb +3 -3
  55. metadata +12 -7
@@ -0,0 +1,144 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+
4
+ module Pindo
5
+ class Command
6
+ class Utils < Command
7
+ class Allcopyconfig < Utils
8
+
9
+ include Appselect
10
+
11
+ self.summary = '批量复制所有配置仓库到新的组织前缀'
12
+
13
+ self.description = <<-DESC
14
+ 遍历当前账号下所有Bundle ID配置仓库,
15
+ 批量执行copyconfig命令将每个仓库复制到新的组织前缀下。
16
+
17
+ 支持功能:
18
+
19
+ * 自动遍历所有dev、tool、release的bundle id
20
+
21
+ * 对每个bundle id执行copyconfig复制
22
+
23
+ * 替换组织前缀和Apple ID
24
+
25
+ * 记录并汇总失败的bundle id
26
+
27
+ 使用示例:
28
+
29
+ $ pindo utils allcopyconfig --to-prefix=com.eyesofstorms --apple-id=eyesofstorms@hotmail.com
30
+
31
+ 注意事项:
32
+
33
+ * 确保目标组织在Gitee上有创建仓库的权限
34
+
35
+ * 已存在的目标仓库会被跳过
36
+ DESC
37
+
38
+ self.arguments = []
39
+
40
+ def self.options
41
+ [
42
+ ['--to-prefix', '目标组织前缀 (如 com.eyesofstorms)'],
43
+ ['--apple-id', '新的Apple开发者账号邮箱']
44
+ ].concat(super)
45
+ end
46
+
47
+ def initialize(argv)
48
+ @to_prefix = argv.option('to-prefix')
49
+ @new_apple_id = argv.option('apple-id')
50
+ super
51
+ end
52
+
53
+ def validate!
54
+ super
55
+ help! "请通过 --to-prefix 指定目标组织前缀 (如 com.eyesofstorms)" if @to_prefix.nil? || @to_prefix.empty?
56
+ help! "请通过 --apple-id 指定新的Apple开发者账号" if @new_apple_id.nil? || @new_apple_id.empty?
57
+ end
58
+
59
+ def run
60
+ @dev_bundle_id_array = all_dev_bundleid()
61
+ @tool_bundle_id_array = all_tool_bundleid()
62
+ @deploy_bundle_id_array = all_release_bundleid()
63
+ all_bundle_ids = @dev_bundle_id_array + @deploy_bundle_id_array + @tool_bundle_id_array
64
+
65
+ puts "目标前缀: #{@to_prefix}"
66
+ puts "目标 Apple ID: #{@new_apple_id}"
67
+ puts "共 #{all_bundle_ids.length} 个 Bundle ID 需要复制"
68
+ puts
69
+
70
+ success_count = 0
71
+ skip_count = 0
72
+ failed_ids = []
73
+
74
+ all_bundle_ids.each_with_index do |from_bundle_id, index|
75
+ if from_bundle_id.include?("*")
76
+ # 通配符 bundle id: com.heroneverdie101.* -> 仓库名 com.heroneverdie101
77
+ clean_from = from_bundle_id.gsub(".*", "")
78
+ new_bundle_id = @to_prefix
79
+
80
+ puts "=" * 60
81
+ puts "[#{index + 1}/#{all_bundle_ids.length}] #{clean_from} -> #{new_bundle_id}"
82
+ puts "=" * 60
83
+
84
+ begin
85
+ args_temp = []
86
+ args_temp << new_bundle_id
87
+ args_temp << "--from=#{clean_from}"
88
+ args_temp << "--apple-id=#{@new_apple_id}"
89
+ Pindo::Command::Utils::Copyconfig.run(args_temp)
90
+ success_count += 1
91
+ rescue => err
92
+ puts " 失败: #{err.message}"
93
+ failed_ids << clean_from
94
+ end
95
+
96
+ puts
97
+ next
98
+ end
99
+
100
+ # 计算新 bundle id: 替换前缀
101
+ from_parts = from_bundle_id.split('.')
102
+ if from_parts.length < 3
103
+ puts "[#{index + 1}/#{all_bundle_ids.length}] #{from_bundle_id} — 格式不合法,跳过"
104
+ skip_count += 1
105
+ next
106
+ end
107
+
108
+ app_name_parts = from_parts[2..]
109
+ new_bundle_id = "#{@to_prefix}.#{app_name_parts.join('.')}"
110
+
111
+ puts "=" * 60
112
+ puts "[#{index + 1}/#{all_bundle_ids.length}] #{from_bundle_id} -> #{new_bundle_id}"
113
+ puts "=" * 60
114
+
115
+ begin
116
+ args_temp = []
117
+ args_temp << new_bundle_id
118
+ args_temp << "--from=#{from_bundle_id}"
119
+ args_temp << "--apple-id=#{@new_apple_id}"
120
+ Pindo::Command::Utils::Copyconfig.run(args_temp)
121
+ success_count += 1
122
+ rescue => err
123
+ puts " 失败: #{err.message}"
124
+ failed_ids << from_bundle_id
125
+ end
126
+
127
+ puts
128
+ end
129
+
130
+ # 汇总
131
+ puts "=" * 60
132
+ puts "完成: #{success_count} 成功, #{failed_ids.length} 失败, #{skip_count} 跳过"
133
+
134
+ if !failed_ids.empty?
135
+ puts
136
+ puts "失败的 Bundle ID:"
137
+ failed_ids.each { |bid| puts " #{bid}" }
138
+ end
139
+ end
140
+
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,207 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'pindo/base/git_handler'
4
+ require 'pindo/config/build_info_manager'
5
+
6
+ module Pindo
7
+ class Command
8
+ class Utils < Command
9
+ class Copyconfig < Utils
10
+
11
+ self.summary = '从已有配置仓库复制创建新的配置仓库,替换bundle id前缀'
12
+
13
+ self.description = <<-DESC
14
+ 从已有的配置仓库复制内容创建新的配置仓库,
15
+ 并将config.json中所有bundle id的组织前缀替换为新的前缀。
16
+
17
+ 支持功能:
18
+
19
+ * 在Gitee上创建新的配置仓库
20
+
21
+ * 复制源仓库的所有内容到新仓库
22
+
23
+ * 自动替换config.json中所有bundle id的组织前缀
24
+
25
+ * 只修改config.json, 其他文件保持不变
26
+
27
+ 使用示例:
28
+
29
+ $ pindo utils copyconfig com.neworg.app --from=com.oldorg.app
30
+
31
+ 注意事项:
32
+
33
+ * 源仓库必须已存在
34
+
35
+ * 新仓库名称不能与已有仓库重名
36
+ DESC
37
+
38
+ self.arguments = [
39
+ CLAide::Argument.new('new_bundle_id', false)
40
+ ]
41
+
42
+ def self.options
43
+ [
44
+ ['--from', '源配置仓库的bundle id'],
45
+ ['--apple-id', '新的Apple开发者账号邮箱']
46
+ ].concat(super)
47
+ end
48
+
49
+ def initialize(argv)
50
+ @new_bundle_id = argv.shift_argument
51
+ @from_bundle_id = argv.option('from')
52
+ @new_apple_id = argv.option('apple-id')
53
+ super
54
+ end
55
+
56
+ def validate!
57
+ super
58
+ help! "请指定新的 bundle id" if @new_bundle_id.nil? || @new_bundle_id.empty?
59
+ help! "请通过 --from 指定源 bundle id" if @from_bundle_id.nil? || @from_bundle_id.empty?
60
+ end
61
+
62
+ def run
63
+ # 提取组织前缀: com.heroneverdie101.xxx -> com.heroneverdie101
64
+ from_parts = @from_bundle_id.split('.')
65
+ new_parts = @new_bundle_id.split('.')
66
+
67
+ if from_parts.length < 2 || new_parts.length < 2
68
+ puts "bundle id 格式错误,至少需要两段 (如 com.org)"
69
+ return
70
+ end
71
+
72
+ from_prefix = from_parts[0..1].join('.')
73
+ new_prefix = new_parts[0..1].join('.')
74
+
75
+ puts "源仓库: #{@from_bundle_id}"
76
+ puts "新仓库: #{@new_bundle_id}"
77
+ puts "前缀替换: #{from_prefix} -> #{new_prefix}"
78
+ puts
79
+
80
+ # 拉取源仓库
81
+ puts "拉取源配置仓库..."
82
+ source_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: @from_bundle_id)
83
+ source_config = File.join(source_dir, "config.json")
84
+
85
+ unless File.exist?(source_config)
86
+ puts "源仓库 #{@from_bundle_id} 中不存在 config.json"
87
+ return
88
+ end
89
+
90
+ # 创建新仓库
91
+ puts "创建新配置仓库 #{@new_bundle_id}..."
92
+ require_relative '../../client/giteeclient'
93
+
94
+ pindo_single_config = Pindoconfig.instance
95
+ gitee_client = GiteeClient.new(access_token: pindo_single_config.gitee_api_key)
96
+
97
+ owner_org = pindo_single_config.build_test_org
98
+
99
+ puts "目标组织: #{owner_org}"
100
+
101
+ success = gitee_client.gitee_create_repo(
102
+ owner: owner_org,
103
+ repo_name: @new_bundle_id,
104
+ public_type: 2
105
+ )
106
+
107
+ unless success
108
+ puts "创建仓库失败,仓库可能已存在"
109
+ return
110
+ end
111
+
112
+ # 将新仓库注册到 git_base_url.json,确保 clong_buildconfig_repo 能找到正确的 org
113
+ build_info_manager = Pindo::BuildInfoManager.share_instance
114
+ build_info_manager.modify_repo_setting(
115
+ repo_name: @new_bundle_id,
116
+ owner_org: owner_org
117
+ )
118
+
119
+ Funlog.instance.fancyinfo_update("等待 Gitee 仓库初始化...")
120
+ sleep 2
121
+
122
+ # 克隆新仓库
123
+ new_config_dir = nil
124
+ 3.times do |i|
125
+ begin
126
+ new_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: @new_bundle_id)
127
+ break if new_config_dir && File.exist?(new_config_dir)
128
+ rescue => e
129
+ if i < 2
130
+ Funlog.instance.fancyinfo_update("克隆失败 (#{i + 1}/3),3秒后重试...")
131
+ sleep 3
132
+ else
133
+ puts "克隆仓库失败: #{e.message}"
134
+ return
135
+ end
136
+ end
137
+ end
138
+
139
+ # 复制源仓库所有内容到新仓库
140
+ puts "复制源仓库内容..."
141
+ Dir.glob(File.join(source_dir, '*'), File::FNM_DOTMATCH).each do |item|
142
+ basename = File.basename(item)
143
+ next if basename == '.' || basename == '..' || basename == '.git'
144
+ FileUtils.cp_r(item, new_config_dir)
145
+ end
146
+
147
+ # 修改 config.json
148
+ new_config_file = File.join(new_config_dir, "config.json")
149
+ if File.exist?(new_config_file)
150
+ config_json = JSON.parse(File.read(new_config_file))
151
+
152
+ # 替换所有 bundle id 的组织前缀
153
+ replace_prefix_in_hash(config_json, from_prefix, new_prefix)
154
+ puts "已替换 config.json 中的 #{from_prefix} -> #{new_prefix}"
155
+
156
+ # 更新 Apple ID
157
+ if @new_apple_id && !@new_apple_id.empty?
158
+ if config_json['account_info'] && config_json['account_info']['apple_acount_id']
159
+ old_apple_id = config_json['account_info']['apple_acount_id']
160
+ config_json['account_info']['apple_acount_id'] = @new_apple_id
161
+ puts "已替换 apple_acount_id: #{old_apple_id} -> #{@new_apple_id}"
162
+ end
163
+ end
164
+
165
+ File.open(new_config_file, "w") do |f|
166
+ f.write(JSON.pretty_generate(config_json) + "\n")
167
+ end
168
+ end
169
+
170
+ # 只提交 config.json
171
+ Pindo::GitHandler.git_addpush_repo(
172
+ path: new_config_dir,
173
+ message: "init config from #{@from_bundle_id}"
174
+ )
175
+
176
+ puts
177
+ puts "配置仓库创建完成: #{new_config_dir}"
178
+ end
179
+
180
+ private
181
+
182
+ # 递归替换 Hash 中所有字符串值的前缀
183
+ def replace_prefix_in_hash(obj, from_prefix, new_prefix)
184
+ case obj
185
+ when Hash
186
+ obj.each do |key, value|
187
+ if value.is_a?(String)
188
+ obj[key] = value.gsub(from_prefix, new_prefix)
189
+ else
190
+ replace_prefix_in_hash(value, from_prefix, new_prefix)
191
+ end
192
+ end
193
+ when Array
194
+ obj.each_with_index do |value, i|
195
+ if value.is_a?(String)
196
+ obj[i] = value.gsub(from_prefix, new_prefix)
197
+ else
198
+ replace_prefix_in_hash(value, from_prefix, new_prefix)
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ end
205
+ end
206
+ end
207
+ end
@@ -75,7 +75,7 @@ module Pindo
75
75
 
76
76
  Funlog.instance.fancyinfo_start("正在生成icon...")
77
77
  begin
78
- XcodeResHelper.create_icons(icon_name: icon_name, new_icon_dir: new_icon_dir)
78
+ XcodeResHelper.create_icons(icon_name: icon_name, new_icon_dir: new_icon_dir, proj_dir: Dir.pwd)
79
79
  Funlog.instance.fancyinfo_success("生成icon成功!")
80
80
  rescue StandardError => e
81
81
  Funlog.instance.fancyinfo_error("生成icon失败!")
@@ -101,4 +101,4 @@ module Pindo
101
101
  end
102
102
  end
103
103
  end
104
- end
104
+ end
@@ -0,0 +1,199 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'spaceship'
4
+ require 'pindo/module/appstore/bundleid_helper'
5
+ require 'pindo/base/git_handler'
6
+ require 'pindo/config/build_info_manager'
7
+
8
+ module Pindo
9
+ class Command
10
+ class Utils < Command
11
+ class Renewbundleid < Utils
12
+
13
+ include Appselect
14
+
15
+ self.summary = '从Apple开发者中心同步所有bundle id的capabilities到config.json'
16
+
17
+ self.description = <<-DESC
18
+ 从Apple Developer Portal读取当前账号下所有Bundle ID的Capability状态,
19
+ 写入各项目config.json的capabilities字段并提交到Git仓库。
20
+
21
+ 支持功能:
22
+
23
+ * 批量读取所有Bundle ID的Capability状态
24
+
25
+ * 自动识别App Group、iCloud容器的关联ID
26
+
27
+ * 将capabilities写入config.json并提交到Git仓库
28
+
29
+ * 支持dry-run预览模式
30
+
31
+ 使用示例:
32
+
33
+ $ pindo utils renewbundleid # 同步所有bundle id的capabilities
34
+
35
+ $ pindo utils renewbundleid --dry-run # 预览模式,不修改文件
36
+
37
+ 注意事项:
38
+
39
+ * 确保已登录Apple Developer账号
40
+
41
+ * 该操作会修改所有相关项目的config.json
42
+ DESC
43
+
44
+ self.arguments = []
45
+
46
+ def self.options
47
+ [
48
+ ['--dry-run', '预览模式,只显示差异不修改文件']
49
+ ].concat(super)
50
+ end
51
+
52
+ def initialize(argv)
53
+ @dry_run = argv.flag?('dry-run', false)
54
+ super
55
+ end
56
+
57
+ def run
58
+ @dev_bundle_id_array = all_dev_bundleid()
59
+ @tool_bundle_id_array = all_tool_bundleid()
60
+ @deploy_bundle_id_array = all_release_bundleid()
61
+ all_bundle_ids = @dev_bundle_id_array + @deploy_bundle_id_array + @tool_bundle_id_array
62
+
63
+ puts "共 #{all_bundle_ids.length} 个 Bundle ID 需要处理"
64
+ puts
65
+
66
+ # 只登录一次
67
+ first_config = load_first_config(all_bundle_ids)
68
+ if first_config.nil?
69
+ puts "无法加载任何 config.json,退出"
70
+ return
71
+ end
72
+
73
+ apple_id = first_config.dig('account_info', 'apple_acount_id')
74
+ if apple_id.nil? || apple_id.empty? || apple_id.include?("__________")
75
+ puts "config.json 中缺少有效的 Apple ID"
76
+ return
77
+ end
78
+
79
+ puts "Login #{apple_id}..."
80
+ Spaceship.login(apple_id.to_s)
81
+ Spaceship.select_team
82
+ puts
83
+
84
+ success_count = 0
85
+ fail_count = 0
86
+ skip_count = 0
87
+
88
+ all_bundle_ids.each do |bundle_id|
89
+ if bundle_id.include?("*")
90
+ bundle_id = bundle_id.gsub(".*", "")
91
+ end
92
+
93
+ begin
94
+ result = update_bundleid_capabilities(bundle_id: bundle_id)
95
+ case result
96
+ when :success then success_count += 1
97
+ when :skip then skip_count += 1
98
+ end
99
+ rescue => err
100
+ puts " #{bundle_id} — 失败: #{err.message}"
101
+ fail_count += 1
102
+ end
103
+ end
104
+
105
+ puts
106
+ puts "完成: #{success_count} 成功, #{fail_count} 失败, #{skip_count} 跳过"
107
+ end
108
+
109
+ private
110
+
111
+ def load_first_config(bundle_ids)
112
+ bundle_ids.each do |bundle_id|
113
+ bid = bundle_id.include?("*") ? bundle_id.gsub(".*", "") : bundle_id
114
+ begin
115
+ app_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: bid)
116
+ config_file = File.join(app_config_dir, "config.json")
117
+ if File.exist?(config_file)
118
+ return JSON.parse(File.read(config_file))
119
+ end
120
+ rescue
121
+ next
122
+ end
123
+ end
124
+ nil
125
+ end
126
+
127
+ def update_bundleid_capabilities(bundle_id: nil)
128
+ # 获取 config 仓库目录
129
+ app_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: bundle_id)
130
+ config_file = File.join(app_config_dir, "config.json")
131
+
132
+ unless File.exist?(config_file)
133
+ puts " #{bundle_id} — config.json 不存在,跳过"
134
+ return :skip
135
+ end
136
+
137
+ config_json = JSON.parse(File.read(config_file))
138
+ app_info = config_json['app_info']
139
+
140
+ if app_info.nil? || app_info['app_identifier'].nil? || app_info['app_identifier'].empty?
141
+ puts " #{bundle_id} — 缺少 app_identifier,跳过"
142
+ return :skip
143
+ end
144
+
145
+ main_bundle_id = app_info['app_identifier']
146
+ puts "读取 #{main_bundle_id} 的 Capability..."
147
+
148
+ capabilities = Pindo::BundleIdHelper.fetch_capabilities_from_portal(bundle_id: main_bundle_id)
149
+
150
+ if capabilities.nil?
151
+ puts " #{main_bundle_id} — Portal 中未找到,跳过"
152
+ return :skip
153
+ end
154
+
155
+ # 显示 capabilities
156
+ capabilities.each do |key, value|
157
+ puts " #{key}: #{value.is_a?(String) ? "\"#{value}\"" : value}"
158
+ end
159
+
160
+ if @dry_run
161
+ old_capabilities = app_info['capabilities'] || {}
162
+ has_diff = false
163
+ capabilities.each do |key, new_value|
164
+ old_value = old_capabilities[key]
165
+ if old_value.nil?
166
+ puts " + #{key}: #{new_value.is_a?(String) ? "\"#{new_value}\"" : new_value}"
167
+ has_diff = true
168
+ elsif old_value != new_value
169
+ puts " ~ #{key}: #{old_value} -> #{new_value}"
170
+ has_diff = true
171
+ end
172
+ end
173
+ puts " (无差异)" unless has_diff
174
+ puts
175
+ return :success
176
+ end
177
+
178
+ # 写入 config.json
179
+ config_json['app_info']['capabilities'] = capabilities
180
+ File.open(config_file, "w") do |f|
181
+ f.write(JSON.pretty_generate(config_json) + "\n")
182
+ end
183
+
184
+ # 提交到 Git 仓库
185
+ Pindo::GitHandler.git_addpush_repo(
186
+ path: app_config_dir,
187
+ message: "sync capabilities from Apple Developer Portal",
188
+ commit_file_params: ["config.json"]
189
+ )
190
+
191
+ puts " #{main_bundle_id} — capabilities 已同步"
192
+ puts
193
+ :success
194
+ end
195
+
196
+ end
197
+ end
198
+ end
199
+ end