pindo 5.20.8 → 5.20.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f5a6e7629e145e28daaf6e8bd9f5ef838a47a5eb064f02828a158eb9483b283
4
- data.tar.gz: 320e0f2169ca80df136fdf09ca6ac21da7368405c39e763f7f5e92fe2717a7a4
3
+ metadata.gz: ae50b918737d06a03fee40e06d31c3833762cabcbbf7425cf9b09da950dc3246
4
+ data.tar.gz: 38373f9ab3fd41bb20e31a56d171afce72b3a93610e583a2e191f013319363cf
5
5
  SHA512:
6
- metadata.gz: c216eeacfa2afc59bb33b1195459acbdebe880c9aee6d59c07b52fa080c564861786a17bccef0f23c1f17976e92f892fe6b94a97fdcdd519e51a927220bc3108
7
- data.tar.gz: dcead01b8d154b1ec138dcc489b509307e5cef5ce090fb34c214c32ba2af8d6f76e0665bac5a6eece1b307090621842c45b79955b74d72b621b8d0545844ec71
6
+ metadata.gz: f3af21bb72d61fe617aa675afcdec5c00041c8c570983ea362b66c517f7e15eaa352e67bec268d90e59e350a6143a42eecdfd04682a4647baab312b58596583b
7
+ data.tar.gz: ca8b7b1f91b3a26b8a35a9d5182998ed868b767dad52936419460f637f2c7183a96132bf354da33a3a3d2ec348a93b245101c40750b0c6316dda2dcaa841b175
@@ -375,10 +375,10 @@ module Pindo
375
375
  if local_branch_exists?(local_repo_dir:local_repo_dir, branch:new_branch)
376
376
  git!(%W(-C #{local_repo_dir} checkout #{new_branch}))
377
377
  else
378
- if !remote_branch_exists?(local_repo_dir:local_repo_dir, branch:new_branch)
379
- git!(%W(-C #{local_repo_dir} checkout -b #{new_branch}))
378
+ if remote_branch_exists?(local_repo_dir:local_repo_dir, branch:new_branch)
379
+ git!(%W(-C #{local_repo_dir} checkout -b #{new_branch} origin/#{new_branch}))
380
380
  else
381
- raise Informative, "仓库中的#{new_branch}分支不存在 !!!"
381
+ git!(%W(-C #{local_repo_dir} checkout -b #{new_branch}))
382
382
  end
383
383
  end
384
384
  git!(%W(-C #{local_repo_dir} branch --set-upstream-to=origin/#{new_branch} #{new_branch}))
@@ -119,6 +119,10 @@ module Pindo
119
119
  # 保存参数到实例变量
120
120
  @args_conf = @options[:conf]
121
121
  @args_bundle_id = @options[:bundleid]
122
+
123
+ # 用户显式指定的 Bundle ID(@args_bundle_id 会在 resolve_bundle_id! 中被回填,
124
+ # 这里单独留一份原始值,用于判断是否覆盖工作流名推导出的 Bundle ID)
125
+ @explicit_bundle_id = @options[:bundleid]
122
126
  @build_type = @options[:build_type] || 'dev'
123
127
 
124
128
  # 标准化构建类型(dev -> development, release -> appstore)
@@ -331,7 +335,9 @@ module Pindo
331
335
 
332
336
  build_options = {
333
337
  project_path: ios_project_path,
334
- bundle_id: config[:bundle_id],
338
+ # 仅传用户显式指定的值:非空时覆盖工作流名推导出的 Bundle ID,
339
+ # 为空时构建任务保持原有的工作流推导行为
340
+ bundle_id: @explicit_bundle_id,
335
341
  app_info_obj: config[:app_info_obj],
336
342
  workflow_info: config[:workflow_info],
337
343
  # Git 版本参数
@@ -211,6 +211,7 @@ module Pindo
211
211
  bundle_id_array: bundle_id_array,
212
212
  cert_type: cert_type,
213
213
  platform_type: @platform_type,
214
+ project_dir: project_dir,
214
215
  match_flag: @match_flag
215
216
  )
216
217
  else
@@ -1,3 +1,4 @@
1
+ require 'open3'
1
2
  require 'pindo/module/xcode/xcode_build_helper'
2
3
 
3
4
  module Pindo
@@ -59,6 +60,21 @@ module Pindo
59
60
  config_parser
60
61
  end
61
62
 
63
+ # 检查证书是否已安装到 Keychain
64
+ #
65
+ # fastlane 的 CertChecker.installed? 会先联网安装 Apple 中间证书(WWDR / Developer ID),
66
+ # 使用的是无重试的 curl -f,Apple CDN 偶发 403 时会抛出 FastlaneError 中断整个证书流程。
67
+ # 这里捕获该异常并降级为不联网的本地签名身份比对。
68
+ #
69
+ # @param cert_path [String] 证书文件路径
70
+ # @return [Boolean] 证书是否已安装
71
+ def certificate_installed?(cert_path)
72
+ FastlaneCore::CertChecker.installed?(cert_path, in_keychain: nil)
73
+ rescue FastlaneCore::Interface::FastlaneError => e
74
+ Funlog.instance.fancyinfo_error("安装 Apple 中间证书失败(#{e.message}),改用本地签名身份比对")
75
+ local_identity_installed?(cert_path)
76
+ end
77
+
62
78
  # 验证并保存证书信息
63
79
  #
64
80
  # 验证证书信息非空,保存到全局配置,提取 Team ID
@@ -320,6 +336,16 @@ module Pindo
320
336
  # 私有辅助方法
321
337
  # ========================================
322
338
 
339
+ # 不联网检查证书是否已在本地代码签名身份中
340
+ #
341
+ # @param cert_path [String] 证书文件路径
342
+ # @return [Boolean] 证书是否已安装
343
+ def local_identity_installed?(cert_path)
344
+ fingerprint = FastlaneCore::CertChecker.sha1_fingerprint(cert_path)
345
+ identities, _stderr, _status = Open3.capture3("security", "find-identity", "-v", "-p", "codesigning")
346
+ identities.include?(fingerprint)
347
+ end
348
+
323
349
  # 配置项目级签名设置
324
350
  def configure_project_level_signing(project, cert_type, platform_type)
325
351
  signing_identity = determine_signing_identity(cert_type, platform_type)
@@ -204,7 +204,7 @@ module Pindo
204
204
  if Pindo::CertHelper.isMac?
205
205
 
206
206
  keychain_name = "login.keychain"
207
- if FastlaneCore::CertChecker.installed?(cert_path, in_keychain: nil)
207
+ if certificate_installed?(cert_path)
208
208
  Funlog.instance.fancyinfo_success("证书#{File.basename(cert_path)}已安装,无需重复安装!")
209
209
  else
210
210
 
@@ -90,7 +90,7 @@ module Pindo
90
90
  end
91
91
 
92
92
  # HTTPS 模式不支持创建证书
93
- def create_and_install_certs(apple_id:, bundle_id_array:, cert_type:, platform_type:)
93
+ def create_and_install_certs(apple_id:, bundle_id_array:, cert_type:, platform_type:, project_dir: nil)
94
94
  raise_unsupported_error("创建证书")
95
95
  end
96
96
 
@@ -388,7 +388,7 @@ module Pindo
388
388
  keychain_name = "login.keychain"
389
389
 
390
390
  # 检查证书是否已安装
391
- if FastlaneCore::CertChecker.installed?(cert_path, in_keychain: nil)
391
+ if certificate_installed?(cert_path)
392
392
  Funlog.instance.fancyinfo_success("证书已安装") if debug_mode?
393
393
  else
394
394
  # 获取 Keychain 密码
@@ -564,7 +564,10 @@ module Pindo
564
564
 
565
565
  # 抛出不支持的操作错误
566
566
  def raise_unsupported_error(operation)
567
- raise Informative, "CustomHttpsCertOperator (HTTPS 模式) 不支持 #{operation} 操作。HTTPS 模式仅支持获取和安装已有证书。"
567
+ raise Informative, "CustomHttpsCertOperator (HTTPS 模式) 不支持 #{operation} 操作。HTTPS 模式仅支持获取和安装已有证书。\n" \
568
+ "如需创建证书,请使用:\n" \
569
+ " pindo ios cert --renew --match\n" \
570
+ "或:pindo ios cert --renew --cert-mode=match --storage=git"
568
571
  end
569
572
  end
570
573
  end
@@ -51,7 +51,7 @@ module Pindo
51
51
  # 这是 fastlane 内部使用的参数,在 App Store Connect API v3.8.0 中已弃用
52
52
  # 该警告不影响功能,fastlane 会自动处理兼容性
53
53
  # 参考:https://docs.fastlane.tools/actions/match/#managed-capabilities
54
- Match::Runner.new.run(config)
54
+ run_match(config)
55
55
 
56
56
  # 从环境变量中读取 match 创建的证书信息(内部方法)
57
57
  provisioning_info_array = extract_provisioning_info_from_match_env(
@@ -97,7 +97,7 @@ module Pindo
97
97
  config = FastlaneCore::Configuration.create(Match::Options.available_options, values)
98
98
 
99
99
  # 从 Git 获取证书(只读模式)
100
- Match::Runner.new.run(config)
100
+ run_match(config)
101
101
 
102
102
  # 从环境变量中读取 match 获取的证书信息(内部方法)
103
103
  provisioning_info_array = extract_provisioning_info_from_match_env(
@@ -124,6 +124,31 @@ module Pindo
124
124
  # Match 特定逻辑:高度自包含
125
125
  # ========================================
126
126
 
127
+ # 运行 fastlane match(禁用 Git hooks)
128
+ #
129
+ # match 会用固定信息提交证书仓库(如 "[fastlane] Updated development and platform ios"),
130
+ # 该信息不符合 Conventional Commits 规范,被 commit-msg 校验 hook 拒绝后
131
+ # 新证书无法推回远端仓库,只能安装到本地。
132
+ # 这里通过 GIT_CONFIG_* 把 core.hooksPath 指向 /dev/null,让 match 的 git 子进程跳过所有 hook。
133
+ #
134
+ # @param config [FastlaneCore::Configuration] match 配置
135
+ def run_match(config)
136
+ index = ENV['GIT_CONFIG_COUNT'].to_i
137
+ saved_env = {
138
+ 'GIT_CONFIG_COUNT' => ENV['GIT_CONFIG_COUNT'],
139
+ "GIT_CONFIG_KEY_#{index}" => ENV["GIT_CONFIG_KEY_#{index}"],
140
+ "GIT_CONFIG_VALUE_#{index}" => ENV["GIT_CONFIG_VALUE_#{index}"]
141
+ }
142
+
143
+ ENV["GIT_CONFIG_KEY_#{index}"] = 'core.hooksPath'
144
+ ENV["GIT_CONFIG_VALUE_#{index}"] = '/dev/null'
145
+ ENV['GIT_CONFIG_COUNT'] = (index + 1).to_s
146
+
147
+ Match::Runner.new.run(config)
148
+ ensure
149
+ saved_env.each { |key, value| ENV[key] = value } if saved_env
150
+ end
151
+
127
152
  # 构建 fastlane match 配置参数
128
153
  #
129
154
  # @param apple_id [String] Apple ID
@@ -16,11 +16,13 @@ module Pindo
16
16
  upload_result["success_urls"] || []
17
17
  end
18
18
 
19
+ # 只拼渲染需要的 width/height,与 JPS 网页端写入 fileUrls 的形态保持一致。
20
+ # 视频不拼 x-oss-process=image/snapshot:那是展示预览图时临时加的参数,
21
+ # 写进 fileUrls 会让请求返回一帧截图而不是视频本身
19
22
  def decorate_media_url(url, file_path)
20
23
  return url if url.to_s.empty? || file_path.to_s.empty?
21
24
 
22
25
  params = []
23
- params << ["x-oss-process", "image/snapshot"] if video_file?(file_path)
24
26
 
25
27
  dimensions = media_dimensions(file_path)
26
28
  if dimensions
@@ -134,12 +134,15 @@ module Pindo
134
134
 
135
135
  puts "\n使用工作流配置更新 iOS 项目:"
136
136
  puts " Workflow Package Name: #{workflow_packname}"
137
+ puts " 指定的 Bundle ID: #{@bundle_id}" if @bundle_id && !@bundle_id.to_s.strip.empty?
137
138
 
138
139
  # 更新 Display Name、Bundle ID、URL Schemes 和 JPS 快捷操作
140
+ # bundle_id 显式传入时优先于工作流名推导,避免 --bundleid 被工作流配置覆盖
139
141
  Pindo::XcodeBuildConfig.update_project_with_workflow(
140
142
  project_dir: @project_path,
141
143
  workflow_packname: workflow_packname,
142
- project_id: project_id
144
+ project_id: project_id,
145
+ bundle_id: @bundle_id
143
146
  )
144
147
 
145
148
  # 下载并替换 Icon,优先使用 packageProjectIcon,为空则回退到 projectIcon
@@ -1,4 +1,5 @@
1
1
  require 'pindo/module/task/model/git_task'
2
+ require 'pindo/base/executable'
2
3
  require 'pindo/base/git_handler'
3
4
  require 'pindo/module/source_files_guard'
4
5
  require 'pindo/module/utils/git_repo_helper'
@@ -133,13 +134,20 @@ module Pindo
133
134
 
134
135
  # 只提交 autobuild 明确注入的源码文件,避免把 Pods、DerivedData 等构建产物带入发布提交。
135
136
  def commit_build_changes(root_dir)
136
- guard_paths = existing_guard_paths(
137
+ guard_paths = reject_ignored_paths(
137
138
  root_dir,
138
- Pindo::BuildSourceFilesGuard.for_project(@project_path)
139
+ existing_guard_paths(
140
+ root_dir,
141
+ Pindo::BuildSourceFilesGuard.for_project(@project_path)
142
+ )
139
143
  )
140
144
  return false if guard_paths.empty?
141
145
 
142
- Pindo::GitHandler.git!(git_command(root_dir, 'add', '--', *guard_paths))
146
+ # -f 是必需的:文件已跟踪、但父目录名匹配 .gitignore 规则时(如本仓库的 build/ 规则
147
+ # 命中 module/task/model/build),普通 add 仍会以非零码退出,让打 tag 整体失败。
148
+ # 危险的「未跟踪 + 被忽略」路径已由 reject_ignored_paths 剔除,此处剩下的都应当提交,
149
+ # -f 只是绕过 advice,不会多纳入任何文件。
150
+ Pindo::GitHandler.git!(git_command(root_dir, 'add', '-f', '--', *guard_paths))
143
151
  staged_files = Pindo::GitHandler.git!(
144
152
  git_command(root_dir, 'diff', '--cached', '--name-only', '--', *guard_paths)
145
153
  ).lines.map(&:strip).reject(&:empty?)
@@ -167,6 +175,36 @@ module Pindo
167
175
  end.uniq
168
176
  end
169
177
 
178
+ # 剔除被 .gitignore 忽略且尚未跟踪的路径。
179
+ #
180
+ # Unity 工程把导出的平台工程目录(GoodPlatform/iOS 等)整体写进 .gitignore,
181
+ # 其中的 project.pbxproj / Info.plist / AppIcon.appiconset 会命中 guard 清单,
182
+ # 但 git add 遇到「被忽略且未跟踪」的路径会以非零码退出,直接让打 tag 任务失败。
183
+ # git check-ignore 不报告已在 index 中的文件,因此已入库的文件仍会照常提交。
184
+ def reject_ignored_paths(root_dir, relative_paths)
185
+ return relative_paths if relative_paths.empty?
186
+
187
+ # check-ignore 不接受 --literal-pathspecs(会以 "pathspec magic not supported" 退出 128),
188
+ # 故不能复用 git_command,这里单独拼参数。
189
+ # core.quotePath=false 是必需的:默认会把中文等非 ASCII 路径转义成 "\344\270\255" 形式,
190
+ # 与输入路径对不上,下面的差集就减不掉,过滤会静默失效。
191
+ output, status = Executable.capture_command(
192
+ 'git',
193
+ ['-C', root_dir, '-c', 'core.quotePath=false', 'check-ignore', '--', *relative_paths],
194
+ capture: :out
195
+ )
196
+
197
+ # 退出码 1 表示没有任何路径被忽略;其余非零码(如 128)说明命令本身出错,
198
+ # 此时不做过滤,保持原有行为把问题暴露给后续的 git add
199
+ return relative_paths unless status.success?
200
+
201
+ ignored = output.lines.map(&:strip).reject(&:empty?)
202
+ return relative_paths if ignored.empty?
203
+
204
+ Funlog.instance.fancyinfo_warning("以下构建注入文件被 .gitignore 忽略,跳过提交: #{ignored.join(', ')}")
205
+ relative_paths - ignored
206
+ end
207
+
170
208
  def git_command(root_dir, command, *arguments)
171
209
  ['--literal-pathspecs', '-C', root_dir, command, *arguments]
172
210
  end
@@ -18,17 +18,23 @@ module Pindo
18
18
  # @param project_dir [String] iOS项目目录路径
19
19
  # @param workflow_packname [String] 工作流的名称(如:"Test Demo")
20
20
  # @param project_id [String] JPS项目ID(可选,用于添加快捷操作)
21
+ # @param bundle_id [String] 显式指定的 Bundle ID(可选,来自 --bundleid)
21
22
  # @return [Boolean] 是否成功更新
22
- def self.update_project_with_workflow(project_dir: nil, workflow_packname: nil, project_id: nil)
23
+ def self.update_project_with_workflow(project_dir: nil, workflow_packname: nil, project_id: nil, bundle_id: nil)
23
24
  raise ArgumentError, "项目目录不能为空" if project_dir.nil?
24
25
  raise ArgumentError, "Workflow Package Name不能为空" if workflow_packname.nil?
25
26
 
26
27
  # 生成各种值
27
28
  display_name = workflow_packname.gsub(/[^a-zA-Z0-9\s]/, '').gsub(/\s+/, '')
28
- bundle_id_suffix = workflow_packname.gsub(/[^a-zA-Z0-9]/, '').downcase
29
- final_bundle_id = "com.heroneverdie101.#{bundle_id_suffix}"
30
29
  package_scheme = workflow_packname.gsub(/[^a-zA-Z0-9]/, '').downcase
31
30
 
31
+ # Bundle ID 优先使用显式传入的值(--bundleid),未传时按工作流名推导。
32
+ # 通配符(如 com.example.*)不能作为工程的 PRODUCT_BUNDLE_IDENTIFIER,
33
+ # 与 BaseCertOperator#configure_target_build_settings 的处理保持一致,退回推导值。
34
+ explicit_bundle_id = bundle_id.to_s.strip
35
+ use_explicit_bundle_id = !explicit_bundle_id.empty? && !explicit_bundle_id.include?("*")
36
+ final_bundle_id = use_explicit_bundle_id ? explicit_bundle_id : "com.heroneverdie101.#{package_scheme}"
37
+
32
38
  project_fullname = Dir.glob(File.join(project_dir, "/*.xcodeproj")).max_by {|f| File.mtime(f)}
33
39
  return false if project_fullname.nil?
34
40
 
@@ -124,7 +130,8 @@ module Pindo
124
130
  end
125
131
 
126
132
  puts " ✓ Display Name 已更新为: #{display_name}"
127
- puts " ✓ Bundle ID 已更新为: #{final_bundle_id}"
133
+ bundle_id_source = use_explicit_bundle_id ? "--bundleid" : "工作流名称"
134
+ puts " ✓ Bundle ID 已更新为: #{final_bundle_id} (来源: #{bundle_id_source})"
128
135
  return true
129
136
  end
130
137
 
data/lib/pindo/version.rb CHANGED
@@ -6,13 +6,13 @@ require 'time'
6
6
 
7
7
  module Pindo
8
8
 
9
- VERSION = "5.20.8"
9
+ VERSION = "5.20.10"
10
10
 
11
11
  class VersionCheck
12
12
  RUBYGEMS_API = 'https://rubygems.org/api/v1/gems/pindo.json'
13
13
  VERSION_INFO_FILE = File.expand_path('~/.pindo/version_info.yml')
14
14
  CHECK_INTERVAL = 5 * 60 * 60 # 5小时检查一次
15
- CONFIG_MIN_VERSION = '1.9.0' # 硬编码的配置版本要求
15
+ CONFIG_MIN_VERSION = '2.1.0' # 硬编码的配置版本要求
16
16
 
17
17
  class << self
18
18
  # 主版本检查方法(保持向后兼容)
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.20.8
4
+ version: 5.20.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - wade
@@ -112,7 +112,7 @@ dependencies:
112
112
  version: '2.7'
113
113
  - - ">="
114
114
  - !ruby/object:Gem::Version
115
- version: 2.7.5
115
+ version: 2.7.6
116
116
  type: :runtime
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
@@ -122,7 +122,7 @@ dependencies:
122
122
  version: '2.7'
123
123
  - - ">="
124
124
  - !ruby/object:Gem::Version
125
- version: 2.7.5
125
+ version: 2.7.6
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: rqrcode
128
128
  requirement: !ruby/object:Gem::Requirement
@@ -532,7 +532,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
532
532
  - !ruby/object:Gem::Version
533
533
  version: 3.0.0
534
534
  requirements: []
535
- rubygems_version: 4.0.10
535
+ rubygems_version: 4.0.11
536
536
  specification_version: 4
537
537
  summary: easy work
538
538
  test_files: []