pindo 5.18.17 → 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.
- checksums.yaml +4 -4
- data/lib/pindo/base/git_handler.rb +17 -29
- data/lib/pindo/command/appstore/adhocbuild.rb +13 -2
- data/lib/pindo/command/appstore/autobuild.rb +2 -1
- data/lib/pindo/command/appstore/iap.rb +58 -54
- data/lib/pindo/config/build_info_manager.rb +31 -0
- data/lib/pindo/config/ios_config_parser.rb +212 -140
- data/lib/pindo/module/appstore/appstore_in_app_purchase.rb +80 -56
- data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +4 -30
- data/lib/pindo/module/task/model/build/ios_build_dev_task.rb +14 -4
- data/lib/pindo/module/task/model/git/git_tag_task.rb +90 -75
- data/lib/pindo/module/task/model/unity/unity_export_task.rb +44 -0
- data/lib/pindo/module/task/task_reporter.rb +45 -0
- data/lib/pindo/module/utils/git_repo_helper.rb +40 -2
- data/lib/pindo/module/xcode/res/xcode_res_handler.rb +25 -4
- data/lib/pindo/module/xcode/xcode_build_config.rb +7 -1
- data/lib/pindo/module/xcode/xcode_build_helper.rb +36 -4
- data/lib/pindo/module/xcode/xcode_res_helper.rb +8 -0
- data/lib/pindo/options/helpers/bundleid_selector.rb +23 -6
- data/lib/pindo/version.rb +1 -1
- metadata +2 -2
|
@@ -352,7 +352,7 @@ module Pindo
|
|
|
352
352
|
if local_exists && Pindo::GitHandler.is_tag_at_head?(git_root_dir: project_dir, tag_name: tag_name)
|
|
353
353
|
if !remote_exists
|
|
354
354
|
# 本地存在且在 HEAD,但远程不存在,推送到远程
|
|
355
|
-
|
|
355
|
+
push_tag_with_verify(project_dir: project_dir, tag_name: tag_name)
|
|
356
356
|
Funlog.instance.fancyinfo_success("推送 Tag 到远程: #{tag_name}")
|
|
357
357
|
else
|
|
358
358
|
Funlog.instance.fancyinfo_success("Tag 已存在且在 HEAD: #{tag_name}")
|
|
@@ -374,10 +374,48 @@ module Pindo
|
|
|
374
374
|
|
|
375
375
|
# 创建并推送 tag
|
|
376
376
|
Pindo::GitHandler.git!(%W(-C #{project_dir} tag #{tag_name}))
|
|
377
|
-
|
|
377
|
+
push_tag_with_verify(project_dir: project_dir, tag_name: tag_name)
|
|
378
378
|
Funlog.instance.fancyinfo_success("创建并推送 Tag: #{tag_name}")
|
|
379
379
|
tag_name
|
|
380
380
|
end
|
|
381
381
|
|
|
382
|
+
# 推送 tag 到远程并校验是否真正推送成功,失败则重试
|
|
383
|
+
# 校验方式为「远程 tag 指向的 commit == 本地 tag commit」,
|
|
384
|
+
# 一次 ls-remote 同时覆盖「存在性」与「指向正确性」
|
|
385
|
+
# @param project_dir [String] 仓库目录
|
|
386
|
+
# @param tag_name [String] tag 名称
|
|
387
|
+
# @param max_retries [Integer] 最大重试次数(默认 3)
|
|
388
|
+
# @return [Boolean] 是否推送成功(失败到达上限会 raise)
|
|
389
|
+
def push_tag_with_verify(project_dir:, tag_name:, max_retries: 3)
|
|
390
|
+
local_commit = Pindo::GitHandler.git!(%W(-C #{project_dir} rev-parse #{tag_name}^{commit})).strip
|
|
391
|
+
|
|
392
|
+
attempt = 0
|
|
393
|
+
loop do
|
|
394
|
+
attempt += 1
|
|
395
|
+
begin
|
|
396
|
+
Pindo::GitHandler.git_remote!(project_dir, %W(-C #{project_dir} push origin #{tag_name}))
|
|
397
|
+
rescue => e
|
|
398
|
+
first_line = e.message.lines.first&.strip
|
|
399
|
+
Funlog.instance.fancyinfo_warning("推送 Tag 失败(第 #{attempt}/#{max_retries} 次): #{first_line}")
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# 校验远程 tag 指向的 commit 是否与本地一致,确认推送成功
|
|
403
|
+
remote_commit = Pindo::GitHandler.remote_tag_commit(local_repo_dir: project_dir, tag_name: tag_name)
|
|
404
|
+
if remote_commit && remote_commit == local_commit
|
|
405
|
+
Funlog.instance.fancyinfo_success("已确认 Tag 推送到远程: #{tag_name}")
|
|
406
|
+
return true
|
|
407
|
+
elsif remote_commit
|
|
408
|
+
Funlog.instance.fancyinfo_warning("远程 Tag 指向不同 commit(远程 #{remote_commit[0..7]} ≠ 本地 #{local_commit[0..7]}),疑似残留旧 Tag: #{tag_name}")
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
if attempt >= max_retries
|
|
412
|
+
raise Informative, "Tag 推送失败,已重试 #{max_retries} 次仍未在远程确认: #{tag_name}"
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
Funlog.instance.fancyinfo_update("远程未确认 Tag,#{attempt}s 后重试推送: #{tag_name}")
|
|
416
|
+
sleep(attempt)
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
382
420
|
end
|
|
383
421
|
end
|
|
@@ -12,13 +12,13 @@ module Pindo
|
|
|
12
12
|
@project_obj = Xcodeproj::Project.open(proj_fullname)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
# 查找工程的 AppIcon.appiconset 目录,找不到返回 nil(不抛异常)
|
|
16
|
+
def find_xcodeproj_icon_path()
|
|
17
17
|
icon_path = nil
|
|
18
18
|
select_target = @project_obj.targets.select { |target| target.respond_to?(:product_type) && target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]) }.first
|
|
19
19
|
|
|
20
20
|
project_dir = @project_obj.project_dir
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
if !select_target.nil?
|
|
23
23
|
file_refs = select_target.resources_build_phase.files_references.select { |file| file.display_name.include?("Assets.xcassets") } || []
|
|
24
24
|
file_refs.each do |file_ref|
|
|
@@ -40,12 +40,33 @@ module Pindo
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
if icon_path.nil? || icon_path.empty? || !File.exist?(icon_path)
|
|
43
|
-
|
|
43
|
+
return nil
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
return icon_path
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
# 工程是否包含 AppIcon 目录(macOS 命令行工具等无 icon 工程返回 false)
|
|
50
|
+
def has_app_icon_dir?()
|
|
51
|
+
!find_xcodeproj_icon_path().nil?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# 工程是否为命令行工具(com.apple.product-type.tool)
|
|
55
|
+
def command_line_tool?()
|
|
56
|
+
tool_uti = Xcodeproj::Constants::PRODUCT_TYPE_UTI[:command_line_tool]
|
|
57
|
+
@project_obj.targets.any? do |target|
|
|
58
|
+
target.respond_to?(:product_type) && !target.product_type.nil? && target.product_type == tool_uti
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def get_xcodeproj_icon_path()
|
|
63
|
+
icon_path = find_xcodeproj_icon_path()
|
|
64
|
+
if icon_path.nil?
|
|
65
|
+
raise Informative, "没有找到Xcode icon 目录"
|
|
66
|
+
end
|
|
67
|
+
return icon_path
|
|
68
|
+
end
|
|
69
|
+
|
|
49
70
|
def install_icon_res(new_icon_dir:nil)
|
|
50
71
|
icon_path = get_xcodeproj_icon_path()
|
|
51
72
|
begin
|
|
@@ -356,7 +356,7 @@ module Pindo
|
|
|
356
356
|
project.save
|
|
357
357
|
|
|
358
358
|
if updated_targets.empty?
|
|
359
|
-
Funlog.instance.
|
|
359
|
+
Funlog.instance.fancyinfo_warning("未找到需要更新的application target(如命令行工具工程),跳过版本更新")
|
|
360
360
|
return false
|
|
361
361
|
else
|
|
362
362
|
Funlog.instance.fancyinfo_success("iOS版本更新完成!")
|
|
@@ -480,6 +480,12 @@ module Pindo
|
|
|
480
480
|
|
|
481
481
|
puts "\n检测到项目 Icon URL: #{icon_url}"
|
|
482
482
|
|
|
483
|
+
# 命令行工具且无 AppIcon 目录时跳过 Icon 替换,视为成功
|
|
484
|
+
if XcodeResHelper.skip_icon_replacement?(proj_dir: project_dir)
|
|
485
|
+
Funlog.instance.fancyinfo_success("命令行工具工程无 AppIcon 目录,跳过 Icon 替换")
|
|
486
|
+
return true
|
|
487
|
+
end
|
|
488
|
+
|
|
483
489
|
# 创建临时目录(所有 icon 处理都在此目录内完成)
|
|
484
490
|
temp_icon_dir = File.join(project_dir, ".pindo_temp_ios_icon")
|
|
485
491
|
icon_download_path = nil
|
|
@@ -699,8 +699,15 @@ module Pindo
|
|
|
699
699
|
project_build_platform = project_obj.root_object.build_configuration_list.get_setting("SDKROOT")["Release"]
|
|
700
700
|
is_macos = !project_build_platform.nil? && project_build_platform.eql?("macosx")
|
|
701
701
|
|
|
702
|
-
#
|
|
703
|
-
|
|
702
|
+
# 命令行工具(com.apple.product-type.tool)产物为裸可执行文件,而非 .app/.ipa
|
|
703
|
+
tool_uti = Xcodeproj::Constants::PRODUCT_TYPE_UTI[:command_line_tool]
|
|
704
|
+
tool_target = project_obj.targets.find { |t| t.respond_to?(:product_type) && t.product_type == tool_uti }
|
|
705
|
+
|
|
706
|
+
# 根据工程类型查找输出文件
|
|
707
|
+
if tool_target
|
|
708
|
+
output_file = find_command_line_tool_output(build_dir: build_dir, target: tool_target)
|
|
709
|
+
puts "命令行工具: 查找可执行文件" if output_file
|
|
710
|
+
elsif is_macos
|
|
704
711
|
# macOS 平台查找 .app 文件
|
|
705
712
|
build_path = File.join(build_dir, "*.app")
|
|
706
713
|
output_file = Dir.glob(build_path).select { |f| File.directory?(f) }.max_by { |f| File.mtime(f) }
|
|
@@ -715,6 +722,24 @@ module Pindo
|
|
|
715
722
|
output_file
|
|
716
723
|
end
|
|
717
724
|
|
|
725
|
+
# 查找命令行工具的输出可执行文件
|
|
726
|
+
# @param build_dir [String] 构建输出目录
|
|
727
|
+
# @param target [Xcodeproj::Project::Object::PBXNativeTarget] 命令行工具 target
|
|
728
|
+
# @return [String, nil] 可执行文件路径
|
|
729
|
+
def find_command_line_tool_output(build_dir:, target:)
|
|
730
|
+
product_name = target.build_configurations.first.build_settings['PRODUCT_NAME']
|
|
731
|
+
product_name = target.name if product_name.nil? || product_name.to_s.include?('$(')
|
|
732
|
+
|
|
733
|
+
# 优先取 gym 导出到 build 根目录的同名可执行文件
|
|
734
|
+
candidate = File.join(build_dir, product_name)
|
|
735
|
+
return candidate if File.file?(candidate)
|
|
736
|
+
|
|
737
|
+
# 回退:build 根目录下任意无扩展名的普通文件(排除 .dSYM 等目录)
|
|
738
|
+
Dir.glob(File.join(build_dir, "*")).find do |f|
|
|
739
|
+
File.file?(f) && File.extname(f).empty?
|
|
740
|
+
end
|
|
741
|
+
end
|
|
742
|
+
|
|
718
743
|
# 获取 Gym 构建参数
|
|
719
744
|
# @param project_fullname [String] 工程文件完整路径
|
|
720
745
|
# @param icloud_id [String, nil] iCloud ID(可选)
|
|
@@ -735,8 +760,15 @@ module Pindo
|
|
|
735
760
|
project_obj = Xcodeproj::Project.open(project_fullname)
|
|
736
761
|
|
|
737
762
|
project_build_platform = project_obj.root_object.build_configuration_list.get_setting("SDKROOT")["Release"]
|
|
738
|
-
main_target = project_obj.targets.select { |target| target.respond_to?(:product_type) && target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]) }.first
|
|
739
|
-
|
|
763
|
+
main_target = project_obj.targets.select { |target| target.respond_to?(:product_type) && !target.product_type.nil? && target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]) }.first
|
|
764
|
+
# 命令行工具等无 application target 的工程,回退到第一个可用 native target
|
|
765
|
+
main_target ||= project_obj.targets.find { |target| target.respond_to?(:product_type) && !target.product_type.nil? }
|
|
766
|
+
if main_target.nil?
|
|
767
|
+
raise Informative, "未找到可编译的 target"
|
|
768
|
+
end
|
|
769
|
+
# 命令行工具通常无 provisioning profile,做 nil 保护
|
|
770
|
+
profile_specifier = main_target.build_configurations.first.build_settings['PROVISIONING_PROFILE_SPECIFIER']
|
|
771
|
+
provisioning_profile_name = profile_specifier.nil? ? "" : profile_specifier.downcase
|
|
740
772
|
|
|
741
773
|
# 确定构建类型和 iCloud 环境
|
|
742
774
|
build_type = "app-store"
|
|
@@ -114,6 +114,14 @@ module Pindo
|
|
|
114
114
|
end
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
+
# 是否应跳过 Icon 替换:工程既无 AppIcon 目录、又是命令行工具时才跳过
|
|
118
|
+
def skip_icon_replacement?(proj_dir:nil)
|
|
119
|
+
xcodeproj_file_name = Dir.glob(File.join(proj_dir, "/*.xcodeproj")).max_by {|f| File.mtime(f)}
|
|
120
|
+
return false if xcodeproj_file_name.nil?
|
|
121
|
+
xcodereshandler = XcodeResHandler.new(proj_fullname: xcodeproj_file_name)
|
|
122
|
+
!xcodereshandler.has_app_icon_dir? && xcodereshandler.command_line_tool?
|
|
123
|
+
end
|
|
124
|
+
|
|
117
125
|
def install_icon(proj_dir:nil, new_icon_dir:nil)
|
|
118
126
|
xcodeproj_file_name = Dir.glob(File.join(proj_dir, "/*.xcodeproj")).max_by {|f| File.mtime(f)}
|
|
119
127
|
xcodereshandler = XcodeResHandler.new(proj_fullname: xcodeproj_file_name)
|
|
@@ -95,17 +95,26 @@ module Pindo
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
# 加载 all_bundleid_group 映射表
|
|
98
|
-
# @return [Hash] group_name => bundle_id 的映射,如 {"fancyapptest" => "com.heroneverdie101.fancyapptest"}
|
|
98
|
+
# @return [Hash, nil] group_name => bundle_id 的映射,如 {"fancyapptest" => "com.heroneverdie101.fancyapptest"};加载失败返回 nil
|
|
99
99
|
def self.load_bundleid_group
|
|
100
100
|
config_file = File.join(pindo_env_configdir, 'bundleid_config.json')
|
|
101
|
-
|
|
101
|
+
unless File.exist?(config_file)
|
|
102
|
+
puts "加载 bundleid_config.json 失败: 文件不存在 #{config_file},请运行 pindo setup 更新配置"
|
|
103
|
+
return nil
|
|
104
|
+
end
|
|
102
105
|
|
|
103
106
|
begin
|
|
104
107
|
config = JSON.parse(File.read(config_file))
|
|
105
|
-
config['all_bundleid_group']
|
|
108
|
+
group = config['all_bundleid_group']
|
|
109
|
+
unless group.is_a?(Hash) && !group.empty?
|
|
110
|
+
puts "加载 bundleid_config.json 失败: all_bundleid_group 缺失或为空 #{config_file},请运行 pindo setup 更新配置"
|
|
111
|
+
return nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
group
|
|
106
115
|
rescue => e
|
|
107
|
-
puts "加载 bundleid_config.json 失败: #{e.message}"
|
|
108
|
-
|
|
116
|
+
puts "加载 bundleid_config.json 失败: #{e.message},请运行 pindo setup 更新配置"
|
|
117
|
+
nil
|
|
109
118
|
end
|
|
110
119
|
end
|
|
111
120
|
|
|
@@ -116,7 +125,15 @@ module Pindo
|
|
|
116
125
|
return nil if group_name.nil? || group_name.empty?
|
|
117
126
|
|
|
118
127
|
group = load_bundleid_group
|
|
119
|
-
group
|
|
128
|
+
return nil unless group
|
|
129
|
+
|
|
130
|
+
bundle_id = group[group_name]
|
|
131
|
+
if bundle_id.nil? || bundle_id.empty?
|
|
132
|
+
puts "解析 Bundle ID 失败: all_bundleid_group 中未找到 #{group_name},请运行 pindo setup 更新配置"
|
|
133
|
+
return nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
bundle_id
|
|
120
137
|
end
|
|
121
138
|
|
|
122
139
|
# 获取 pindo 环境配置目录
|
data/lib/pindo/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pindo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.18.
|
|
4
|
+
version: 5.18.20
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- wade
|
|
@@ -526,7 +526,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
526
526
|
- !ruby/object:Gem::Version
|
|
527
527
|
version: 3.0.0
|
|
528
528
|
requirements: []
|
|
529
|
-
rubygems_version:
|
|
529
|
+
rubygems_version: 4.0.11
|
|
530
530
|
specification_version: 4
|
|
531
531
|
summary: easy work
|
|
532
532
|
test_files: []
|