pod-binary-pack 1.0.0

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.
@@ -0,0 +1,506 @@
1
+ # frozen_string_literal: true
2
+ require 'fileutils'
3
+ require 'json'
4
+ require 'shellwords'
5
+ require 'pathname'
6
+ require_relative 'podspec'
7
+ require_relative 'repo_module'
8
+ require_relative 'github_helper'
9
+ require_relative 'util/string'
10
+ require_relative 'util/file_helper'
11
+
12
+ module Build
13
+ class RepoModuleSource < RepoModule
14
+ # podspec未声明Swift版本时补全的默认版本:部分含Swift的三方库(如LookinServer)root未声明
15
+ # swift_version,纯OC壳工程target又未设SWIFT_VERSION,不补会导致 pod install 报
16
+ # "Unable to determine Swift version";Swift 5 语法在 Xcode 16/27 均可编译
17
+ DEFAULT_SWIFT_VERSION = '5.0'.freeze
18
+
19
+ # 最低支持版本
20
+ attr_accessor :ios_version
21
+
22
+ # 上次发布该版本时podspec.json中记录的commitID(无历史版本时为nil)
23
+ attr_accessor :last_released_commit_id
24
+
25
+ # 源码仓库的校验逻辑
26
+ def validate
27
+ super
28
+
29
+ branch_version = self.class.parse_version_from_branch(branch, release_branch_prefix)
30
+
31
+ # 分支是版本分支(前缀可配置):分支里的版本号必须与打包版本号一致
32
+ if branch_version
33
+ if branch_version != pod_version
34
+ error = "版本分支#{branch}解析出版本号#{branch_version},与传入的打包版本号#{pod_version}不一致,请保持二者相同(或直接缺省--version由分支解析)"
35
+ pusher.push("❌ 打包失败", error)
36
+ Process.exit(-1)
37
+ end
38
+ end
39
+
40
+ # 标准发布版本号(纯数字二/三/四段式,如 1.2 / 1.2.0 / 1.2.2.0)只能在
41
+ # master 分支或版本分支(<定制前缀>_x.y.z)上打包;
42
+ # 非 master、非版本前缀的普通特性分支不允许打标准版本号。
43
+ # 单段、五段及以上、带后缀的版本(如 1.2.2-fix / 1.2.0-beta.1)不属于标准发布版本,不做此约束
44
+ if self.branch != "master" and self.branch != self.pod_version and not self.third #特殊处理
45
+ if standard_release_version?(pod_version) and branch_version.nil?
46
+ error = "标准版本号(#{pod_version},二段/三段/四段式)只能在 master 分支或版本分支上打包," \
47
+ "请将分支命名为 #{release_branch_prefix}_#{pod_version} 或 #{release_branch_prefix}-#{pod_version}(前缀可在 build.yml 配置)," \
48
+ "当前分支 #{self.branch} 不符合规则;带后缀的版本号(如 1.2.0-fix)不受此限制"
49
+ pusher.push("❌ 打包失败", error)
50
+ Process.exit(-1)
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ # 是否为标准发布版本号:纯数字且恰为 2~4 段(1.2 / 1.2.3 / 1.2.3.4)
57
+ def standard_release_version?(version)
58
+ version.to_s.match?(/\A\d+\.\d+(?:\.\d+){0,2}\z/)
59
+ end
60
+
61
+ # @api 锁死分支
62
+ def lock_branch_if_need
63
+ if build_item.snapshot
64
+ Build.log.info("当前源码仓库为SNAPSHOT包,无需锁死分支")
65
+ return
66
+ end
67
+
68
+ if third
69
+ Build.log.info("当前打包为三方库,无需锁死分支")
70
+ return
71
+ end
72
+
73
+ unless hosting.available?
74
+ Build.log.info("当前组件仓库非受支持的代码托管平台, 跳过锁死分支, url = #{ssh_url}")
75
+ return
76
+ end
77
+
78
+ unless repo_info
79
+ Build.log.info("未查询到仓库信息,跳过锁死分支 #{branch}")
80
+ return
81
+ end
82
+
83
+ Build.log.info("当前源码仓库(#{repo_info.full_name})打包模式为正式包,需锁死分支 #{branch}")
84
+ setting_url = hosting.lock_branch(repo_info, branch, page_url)
85
+
86
+ # 推送
87
+ pusher.push("【✅组件分支已锁死无法提交】", "配置地址 #{setting_url}")
88
+
89
+ end
90
+ # @api force_cover这个字段的检测
91
+ def force_cover_validate(repo_cocoapods_source)
92
+
93
+ # http归档git化组件:每次构建基于官方归档重新生成单提交历史,commit不延续,
94
+ # 上次发布的commit不可能包含在本次历史中,包含校验对这类组件无意义
95
+ if Build::GithubHelper.instance.http_source
96
+ Build.log.info("不校验commit信息是否包含上次,原因:http归档组件每次按官方归档重建,commit不延续历史")
97
+ return
98
+ end
99
+
100
+ # 强制覆盖的话 则不需要commit校验
101
+ if build_item.force_cover
102
+ Build.log.info("不校验commit信息是否包含上次,原因:force_cover = false")
103
+ return
104
+ end
105
+
106
+ # 非受支持平台地址 不校验
107
+ unless hosting.available?
108
+ Build.log.info("不校验commit信息是否包含上次,原因:当前组件仓库非受支持的代码托管平台, url = #{ssh_url}")
109
+ return
110
+ end
111
+
112
+ # 未查询到仓库信息 不校验
113
+ unless repo_info
114
+ Build.log.info("不校验commit信息是否包含上次,原因:未查询到当前组件的仓库信息")
115
+ return
116
+ end
117
+
118
+ # 判断cocoapods_source里文件夹是否存在
119
+ pod_name_path = "#{repo_cocoapods_source.path}/#{pod_name}"
120
+ unless File.directory?(pod_name_path)
121
+ Build.log.info("不校验commit信息是否包含上次,原因:repo_cocoapods_source没有当前组件文件夹")
122
+ return
123
+ end
124
+
125
+ # 判断json文件是否存在
126
+ pod_version_path = "#{pod_name_path}/#{pod_version_final}"
127
+ unless File.directory?(pod_version_path)
128
+ Build.log.info("不校验commit信息是否包含上次,原因:repo_cocoapods_source组件文件夹没有当前版本文件夹")
129
+ return
130
+ end
131
+
132
+ podspec_json_path = "#{pod_version_path}/#{pod_name}.podspec.json"
133
+ # 文件不存在 不校验了
134
+ unless File.exist?(podspec_json_path)
135
+ Build.log.info("不校验commit信息是否包含上次,原因:repo_cocoapods_source组件文件夹没有podspec.json文件")
136
+ return
137
+ end
138
+
139
+ json = File.read(podspec_json_path)
140
+ podspec_content = JSON.parse(json)
141
+ # 扩展信息统一读取 build_metadata 嵌套字段
142
+ metadata = podspec_content[PODSPEC_METADATA_KEY] || {}
143
+ commit_id = metadata["commit_id"]
144
+ committer = metadata["committer"]
145
+ commit_msg = metadata["commit_message"]
146
+ commit_time = metadata["commit_time"]
147
+ unless commit_id
148
+ Build.log.info("不校验commit信息是否包含上次,原因:repo_cocoapods_source的podspec.json build_metadata.commit_id为空")
149
+ return
150
+ end
151
+
152
+ # 记录上次发布的commit,供后续判断"本次是否有新提交"
153
+ @last_released_commit_id = commit_id
154
+
155
+ # 校验
156
+ contain = self.hosting.branch_contain_commit?(repo_info, branch, commit_id)
157
+ Build.log.step("(#{File.basename(self.path)})上次发布的commit信息:")
158
+ Build.log.detail("#{commit_id} #{commit_msg} #{commit_time}")
159
+ if contain
160
+ Build.log.detail("校验上次发布 commit 包含关系:通过")
161
+ else
162
+ error = "当前发布分支#{branch}不包含上次发布的#{committer}提交, 请先合并分支再打包或手动选择强制覆盖"
163
+ pusher.push("❌ 打包失败", error)
164
+ Process.exit(-1)
165
+ end
166
+ end
167
+
168
+ # 本次打包的源码是否与上次发布完全一致(当前HEAD就是上次发布的commit)。
169
+ # 一致时源码仓/二进制仓的版本tag无需删除后重新推送(tag仍指向同一个commit)。
170
+ # 三方库(走上游版本tag)、强制覆盖、无历史版本记录时不做该判定。
171
+ def no_new_commit_since_last_release?
172
+ return false if third
173
+ return false if build_item.force_cover
174
+ return false if last_released_commit_id.to_s.empty?
175
+
176
+ same_commit?(last_released_commit_id, last_commit.commit_id)
177
+ end
178
+
179
+ # 比较两个commit标识是否指向同一提交(兼容完整SHA与短SHA互相比较)
180
+ def same_commit?(sha_a, sha_b)
181
+ a = sha_a.to_s.strip.downcase
182
+ b = sha_b.to_s.strip.downcase
183
+ return false if a.empty? || b.empty? || a.length < 7 || b.length < 7
184
+
185
+ a == b || a.start_with?(b) || b.start_with?(a)
186
+ end
187
+
188
+ # podspec所在目录:子目录podspec时以该目录为文件匹配根(与CocoaPods :podspec 语义一致),
189
+ # 默认仍是仓库根目录。必须在 podspec 定位完成(update_podspec)后才有值
190
+ def component_root_dir
191
+ @source_podspec_entry ? File.dirname(@source_podspec_entry) : path
192
+ end
193
+
194
+ # podspec是否位于仓库根目录:false时打包生成的LocalDependencies需用podspec:指向具体文件
195
+ def podspec_at_repo_root?
196
+ source_podspec_entry
197
+ File.dirname(@source_podspec_entry) == File.expand_path(path)
198
+ end
199
+
200
+ # podspec中全部subspec的短名(去掉root前缀),含嵌套subspec;无subspec时返回空数组。
201
+ # json中的name形如 "BSDebugPlugins/DLAM" / "Root/A/B",统一取最后一段
202
+ def podspec_subspec_names
203
+ collect_subspec_names(podspec_content && podspec_content["subspecs"])
204
+ end
205
+
206
+ def collect_subspec_names(subspecs)
207
+ Array(subspecs).flat_map do |subspec|
208
+ name = subspec["name"].to_s.split("/").last
209
+ children = collect_subspec_names(subspec["subspecs"])
210
+ name.empty? ? children : [name] + children
211
+ end
212
+ end
213
+
214
+ # 本次打包实际集成的subspec短名列表(须在podspec定位完成后调用):
215
+ # - 显式指定(build.yml components.<组件>.subspecs 或 --subspecs)时校验存在性后按指定值,
216
+ # 用于互斥subspec组件(如FMDB),全量合并编译必然冲突的场景
217
+ # - 未指定时默认集成podspec全部subspec
218
+ def resolved_build_subspecs
219
+ all = podspec_subspec_names
220
+ return all if all.empty? || build_subspecs.nil?
221
+
222
+ unknown = build_subspecs - all
223
+ unless unknown.empty?
224
+ error = "subspec配置指定了podspec中不存在的名称: #{unknown.join('、')};" \
225
+ "组件#{pod_name}可用的subspec: #{all.join('、')}"
226
+ pusher.push("❌ 打包失败", error)
227
+ Process.exit(-1)
228
+ end
229
+ build_subspecs
230
+ end
231
+
232
+ # root及所有(含嵌套)subspec的扁平化列表
233
+ def all_podspec_specs
234
+ collect_specs(podspec_content)
235
+ end
236
+
237
+ def collect_specs(spec)
238
+ return [] unless spec.is_a?(Hash)
239
+ [spec] + Array(spec["subspecs"]).flat_map { |child| collect_specs(child) }
240
+ end
241
+
242
+ # 全部resource_bundles的bundle名(root+subspecs,去重)
243
+ def all_resource_bundle_names
244
+ all_podspec_specs.flat_map do |spec|
245
+ bundles = spec["resource_bundles"] || spec["resource_bundle"]
246
+ bundles.is_a?(Hash) ? bundles.keys : []
247
+ end.uniq
248
+ end
249
+
250
+ # 全部resources/resource声明的glob(root+subspecs,去重)
251
+ def all_resource_globs
252
+ all_podspec_specs.flat_map do |spec|
253
+ resources = spec["resources"] || spec["resource"]
254
+ case resources
255
+ when Array then resources
256
+ when nil then []
257
+ else [resources]
258
+ end
259
+ end.uniq
260
+ end
261
+
262
+ # 定位源码仓内的podspec文件(.podspec或.podspec.json的绝对路径)
263
+ # 优先级: 显式配置(--podspec-path/build.yml) > 根目录<组件名>.podspec约定 > 递归自动扫描(唯一命中)
264
+ def source_podspec_entry
265
+ return @source_podspec_entry if @source_podspec_entry
266
+
267
+ root_podspec = File.join(path, "#{pod_name}.podspec")
268
+ if podspec_rel_path
269
+ explicit = File.expand_path(podspec_rel_path, path)
270
+ unless File.exist?(explicit)
271
+ error = "配置的podspec路径不存在: #{podspec_rel_path}(相对源码仓根目录),仓库: #{ssh_url}"
272
+ pusher.push("❌ 打包失败", error)
273
+ Process.exit(-1)
274
+ end
275
+ @source_podspec_entry = explicit
276
+ Build.log.detail("使用显式配置的podspec: #{podspec_rel_path}")
277
+ return @source_podspec_entry
278
+ end
279
+
280
+ if File.exist?(root_podspec)
281
+ @source_podspec_entry = root_podspec
282
+ return @source_podspec_entry
283
+ end
284
+
285
+ # 自动扫描:兼容podspec不在根目录/一仓多组件,排除.git与Pods目录
286
+ candidates = Dir.glob(File.join(path, '**', "#{pod_name}.podspec{,.json}"))
287
+ .reject { |p| p.include?('/.git/') || p.include?('/Pods/') }
288
+ .sort_by { |p| p.end_with?('.podspec.json') ? 1 : 0 }
289
+ if candidates.size == 1
290
+ @source_podspec_entry = candidates.first
291
+ rel = Pathname.new(@source_podspec_entry).relative_path_from(Pathname.new(File.expand_path(path))).to_s
292
+ Build.log.detail("根目录未找到podspec,自动扫描命中: #{rel}")
293
+ return @source_podspec_entry
294
+ elsif candidates.size > 1
295
+ rel_list = candidates.map { |p| Pathname.new(p).relative_path_from(Pathname.new(File.expand_path(path))).to_s }
296
+ error = "扫描到多个#{pod_name}的podspec(#{rel_list.join('、')}),无法自动确定,请通过 --podspec-path 或 build.yml components.#{pod_name}.podspec_path 显式指定"
297
+ pusher.push("❌ 打包失败", error)
298
+ Process.exit(-1)
299
+ end
300
+
301
+ error = "podspec文件不存在:源码仓根目录及子目录均未找到 #{pod_name}.podspec(.json),如podspec命名特殊请通过 --podspec-path 指定"
302
+ pusher.push("❌ 打包失败", error)
303
+ Process.exit(-1)
304
+ end
305
+
306
+ # @api podspec文件更新
307
+ def update_podspec
308
+
309
+ entry = source_podspec_entry
310
+
311
+ if entry.end_with?('.podspec.json')
312
+ # 仓库内本就是json podspec,直接使用不做转换
313
+ @podspec_json_path = entry
314
+ else
315
+ # .podspec 生成对应的json(生成后从工作副本删除.podspec,与既有行为一致)
316
+ @podspec_json_path = "#{entry}.json"
317
+ FileUtils.rm_f(@podspec_json_path)
318
+ command = "pod ipc spec #{Shellwords.escape(entry)} >> #{Shellwords.escape(podspec_json_path)}"
319
+ res = system command
320
+ unless res == true
321
+ error = "命令执行失败: #{command}"
322
+ pusher.push("❌ 打包失败", error)
323
+ Process.exit(-1)
324
+ end
325
+ FileUtils.rm_rf(entry)
326
+ end
327
+
328
+ unless File.exist?(podspec_json_path)
329
+ error = "podspec文件不存在"
330
+ pusher.push("❌ 打包失败", error)
331
+ Process.exit(-1)
332
+ end
333
+
334
+ # 处理json文件
335
+ podspec = Podspec.new(podspec_json_path)
336
+ podspec_content = podspec.podspec_content
337
+
338
+ # 显式指定集成subspec(build.yml components.<组件>.subspecs 或 --subspecs)时,
339
+ # 把本地podspec同步剪裁为该集合后再写回:
340
+ # - 互斥subspec组件(如FMDB)即使声明:subspecs,CocoaPods仍会激活default_subspecs
341
+ # 指向的subspec(如standard的libraries: sqlite3),把系统libsqlite3混入
342
+ # SQLCipher加密版产物的链接,必须从spec源头剪掉
343
+ # - default_subspecs指向被剪subspec时一并移除,默认=保留的全部subspec
344
+ removed_subspec_names = []
345
+ if build_subspecs.is_a?(Array) && podspec_content["subspecs"].is_a?(Array)
346
+ all_names = collect_subspec_names(podspec_content["subspecs"])
347
+ unknown = build_subspecs - all_names
348
+ unless unknown.empty?
349
+ error = "subspec配置指定了podspec中不存在的名称: #{unknown.join('、')};" \
350
+ "组件#{pod_name}可用的subspec: #{all_names.join('、')}"
351
+ pusher.push("❌ 打包失败", error)
352
+ Process.exit(-1)
353
+ end
354
+ kept = podspec_content["subspecs"].select do |subspec|
355
+ names = [subspec["name"].to_s.split("/").last] + collect_subspec_names(subspec["subspecs"])
356
+ (names & build_subspecs).any?
357
+ end
358
+ if kept.size < podspec_content["subspecs"].size
359
+ removed_subspec_names = (podspec_content["subspecs"] - kept).map { |s| s["name"] }
360
+ Build.log.detail("本地podspec按配置剪掉未集成的subspec: #{removed_subspec_names.join('、')}")
361
+ podspec_content["subspecs"] = kept
362
+ defaults = case podspec_content["default_subspecs"]
363
+ when String then podspec_content["default_subspecs"].split(",").map { |d| d.to_s.split("/").last.strip }
364
+ when Array then podspec_content["default_subspecs"].map { |d| d.to_s.split("/").last.strip }
365
+ else []
366
+ end.reject(&:empty?)
367
+ podspec_content.delete("default_subspecs") unless defaults.empty? || (defaults - build_subspecs).empty?
368
+ end
369
+ end
370
+
371
+ podspec_content.delete("license")
372
+
373
+ # source改写:
374
+ # - http归档git化组件(克隆内podspec仍带source.http):整体替换为镜像仓git+tag引用,
375
+ # 避免http与git两种来源并存导致CocoaPods解析冲突;tag即git化时在镜像仓打的版本tag
376
+ # - git源组件:替换git地址;非三方库再补version/tag(三方库沿用上游tag)
377
+ if podspec_content["source"].is_a?(Hash) && podspec_content["source"]["http"]
378
+ podspec_content["source"] = {"git" => ssh_url, "tag" => version_tag}
379
+ Build.log.detail("http归档组件source已改写为镜像仓引用: #{ssh_url} (tag: #{version_tag})")
380
+ else
381
+ podspec_content["source"]["git"] = ssh_url
382
+
383
+ unless self.third
384
+ podspec_content["version"] = pod_version_final
385
+ # 一仓多组件时tag带组件名前缀(Foo/1.0.0),默认无前缀
386
+ podspec_content["source"]["tag"] = version_tag
387
+ end
388
+ end
389
+
390
+ # 含Swift源码但未声明Swift版本的podspec补全默认版本,避免纯OC壳工程 pod install 失败
391
+ ensure_swift_version(podspec_content)
392
+
393
+ # 处理有些库因为缺少配置导致的编译问题
394
+ if pod_name == "CocoaHTTPServer"
395
+ podspec_content["pod_target_xcconfig"] = {'GCC_PREPROCESSOR_DEFINITIONS' => ['$(inherited)', 'DD_LEGACY_MACROS=1']}
396
+ elsif pod_name == "Protobuf"
397
+ podspec_content["pod_target_xcconfig"] = {'GCC_PREPROCESSOR_DEFINITIONS' => ['$(inherited)', 'GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1']}
398
+ end
399
+
400
+ # 处理MLeaksFinder公开头文件
401
+ if pod_name == "MLeaksFinder"
402
+ podspec_content["public_header_files"] << "MLeaksFinder/MLeaksMessenger.h"
403
+ end
404
+
405
+ # 工具生成的扩展信息统一收敛到 build_metadata 字段,
406
+ # 嵌套对象会被 CocoaPods 整体忽略,避免自定义key污染/冲突官方podspec属性
407
+ metadata = {
408
+ "address" => http_url,
409
+ "committer" => last_commit.committer,
410
+ "commit_id" => last_commit.commit_id,
411
+ "commit_message" => last_commit.commit_msg,
412
+ "commit_time" => last_commit.commit_time,
413
+ "commit_email" => last_commit.commit_mail,
414
+ "tool_version" => Pod::BinaryPack::VERSION,
415
+ "note" => "这是一份自动生成的文件, 请勿手动修改"
416
+ }
417
+
418
+ # http归档git化组件补充归档溯源信息(原始归档地址与实际计算的sha256)
419
+ github_helper = Build::GithubHelper.instance
420
+ if github_helper.http_source
421
+ metadata["archive_url"] = github_helper.archive_url
422
+ metadata["archive_sha256"] = github_helper.archive_sha_actual if github_helper.archive_sha_actual
423
+ end
424
+
425
+ # 与官方原始podspec存在subspec集合差异(互斥subspec按配置剪裁)时显式说明,
426
+ # 该字段会随podspec_content一并带入二进制spec的build_metadata
427
+ if removed_subspec_names.any?
428
+ metadata["subspec_note"] = "该组件subspec存在互斥关系,本spec与官方原始podspec存在差异:" \
429
+ "按配置仅集成 #{build_subspecs.join('、')},剪掉 #{removed_subspec_names.join('、')}," \
430
+ "default_subspecs 已同步调整;如需其他subspec组合请调整 build.yml components.subspecs 后重新打包"
431
+ end
432
+
433
+ podspec_content[PODSPEC_METADATA_KEY] = metadata
434
+
435
+ # 更新属性
436
+ @podspec_content = podspec_content
437
+ __update_framework_name(podspec_content)
438
+
439
+ # 更新最低版本号
440
+ platforms = podspec_content["platforms"]
441
+ if platforms and platforms.class == Hash and platforms["ios"]
442
+ @ios_version = platforms["ios"]
443
+ end
444
+
445
+ ## 重写文件
446
+ new_file = File.new(podspec_json_path, "w+")
447
+ if new_file
448
+ new_file.syswrite(JSON.pretty_generate(podspec_content))
449
+ end
450
+ end
451
+
452
+ private
453
+
454
+ # podspec本身未声明 swift_version/swift_versions,且root或任一(含嵌套)subspec确实包含
455
+ # .swift源文件时,补全默认Swift版本。纯OC组件/已声明版本的组件不改动
456
+ def ensure_swift_version(spec)
457
+ return if spec['swift_version'] || spec['swift_versions']
458
+ return unless contains_swift_sources?(spec)
459
+
460
+ spec['swift_version'] = DEFAULT_SWIFT_VERSION
461
+ Build.log.detail("podspec未声明swift_version/swift_versions,但root或subspec中检测到Swift源文件," \
462
+ "已自动补全 swift_version=#{DEFAULT_SWIFT_VERSION}(否则纯OC壳工程集成时pod install无法确定Swift版本)")
463
+ end
464
+
465
+ # root及全部subspec的source_files中是否存在.swift文件
466
+ def contains_swift_sources?(spec)
467
+ collect_specs(spec).any? do |sub_spec|
468
+ Array(sub_spec['source_files']).any? do |pattern|
469
+ FileHelper.source_files_under(File.join(component_root_dir, pattern))
470
+ .any? { |file_path| File.extname(file_path).downcase == '.swift' }
471
+ end
472
+ end
473
+ end
474
+
475
+ def __update_framework_name(podspec_content)
476
+ # 如果指定了module_name 就取这个名字,否则就取pod_name作为framework_name
477
+ framework_name = podspec_content["module_name"]
478
+ header_dir = podspec_content["header_dir"]
479
+ if framework_name.nil?
480
+ # 如果没有,就取一下head_dir试试
481
+ framework_name = header_dir ? header_dir : pod_name
482
+ end
483
+
484
+ # 解决pod库名字中+ 和- 被转成_的问题
485
+ framework_name = framework_name.gsub("-", "_")
486
+ framework_name = framework_name.gsub("+", "_")
487
+
488
+ @framework_name = framework_name
489
+ end
490
+
491
+ public def git_tag
492
+ # http归档组件:版本tag在fork阶段就地git化时已处理(镜像仓同名tag默认跳过/force_cover强制覆盖),
493
+ # 且克隆处于tag检出的detached状态,无法走"拉取+打tag"常规流程,直接跳过
494
+ return if Build::GithubHelper.instance.http_source
495
+
496
+ unless self.third
497
+ super
498
+ end
499
+
500
+ if self.third and build_item.force_cover
501
+ super
502
+ end
503
+
504
+ end
505
+ end
506
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'repo'
3
+ require 'xcodeproj'
4
+
5
+ module Build
6
+ class RepoXCode < Repo
7
+ attr_reader :xcworkspace
8
+ attr_reader :scheme
9
+ # @return [Boolean] archive 时是否启用代码签名
10
+ attr_reader :code_signing
11
+ # @return [String, nil] 签名团队ID(仅 code_signing=true 时生效)
12
+ attr_reader :development_team
13
+
14
+ def initialize(path, ssh_url, branch, xcworkspace = nil, scheme = nil,
15
+ code_signing: false, development_team: nil)
16
+ super(path, ssh_url, branch)
17
+ @xcworkspace = xcworkspace
18
+ @scheme = scheme
19
+ @code_signing = code_signing
20
+ @development_team = development_team
21
+ end
22
+
23
+ def pod_update
24
+ current = FileUtils.pwd
25
+ Dir.chdir(self.path)
26
+ dir_name = File.basename(self.path)
27
+
28
+ command = "pod update"
29
+ Build.log.step("(#{dir_name})执行pod命令")
30
+ Build.log.debug(command)
31
+ res = system command
32
+ unless res == true
33
+ error = "pod命令执行失败: #{command}"
34
+ pusher.push("❌ 打包失败", error)
35
+ Process.exit(-1)
36
+ end
37
+
38
+ Dir.chdir(current)
39
+ end
40
+ end
41
+ end