pindo 5.20.3 → 5.20.5
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 +97 -73
- data/lib/pindo/command/android/autobuild.rb +28 -19
- data/lib/pindo/command/ios/autobuild.rb +43 -42
- data/lib/pindo/command/jps/apptest.rb +8 -3
- data/lib/pindo/command/jps/media.rb +2 -1
- data/lib/pindo/command/unity/autobuild.rb +18 -7
- data/lib/pindo/command/web/autobuild.rb +28 -19
- data/lib/pindo/module/pgyer/pgyerhelper.rb +139 -51
- data/lib/pindo/module/source_files_guard.rb +12 -3
- data/lib/pindo/module/task/model/git/git_commit_task.rb +6 -0
- data/lib/pindo/module/task/model/git/git_tag_task.rb +8 -2
- data/lib/pindo/module/task/model/git_task.rb +27 -2
- data/lib/pindo/module/task/model/jps/jps_bind_package_task.rb +64 -9
- data/lib/pindo/module/task/model/jps/jps_upload_media_task.rb +14 -5
- data/lib/pindo/module/task/model/jps/jps_workflow_message_task.rb +32 -14
- data/lib/pindo/module/task/model/jps_task.rb +20 -0
- data/lib/pindo/module/task/model/nuget/nuget_upload_task.rb +6 -2
- data/lib/pindo/version.rb +1 -1
- metadata +4 -4
|
@@ -366,9 +366,13 @@ module Pindo
|
|
|
366
366
|
tasks << message_task
|
|
367
367
|
end
|
|
368
368
|
|
|
369
|
-
# 8.
|
|
370
|
-
|
|
371
|
-
|
|
369
|
+
# 8. 获取 Git 管理类型的工作流(media、bind、send 共用,不同于 HTML 上传的包工作流)
|
|
370
|
+
# commit 记录挂在 Git 工作流下,媒体附件、包绑定、工作流消息都按它定位
|
|
371
|
+
git_app_info_obj = nil
|
|
372
|
+
git_workflow_info = nil
|
|
373
|
+
if @args_media_flag || @args_bind_flag || @args_send_flag
|
|
374
|
+
# 取不到就让异常冒泡:media/bind/send 都依赖它,静默跳过会让命令
|
|
375
|
+
# 明明没做用户要求的事却以 0 退出
|
|
372
376
|
git_app_info_obj, git_workflow_info = PgyerHelper.share_instace.prepare_upload(
|
|
373
377
|
working_directory: config[:project_path],
|
|
374
378
|
conf: @args_conf,
|
|
@@ -376,48 +380,53 @@ module Pindo
|
|
|
376
380
|
manage_type: "git"
|
|
377
381
|
)
|
|
378
382
|
|
|
383
|
+
unless git_app_info_obj && git_workflow_info
|
|
384
|
+
raise Informative, "未获取到 Git 类型的工作流;请在 JPS 后台配置 manage_type=git 的工作流"
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# 9. 创建媒体附件上传任务(如果需要,依赖 Git 提交/打 Tag 任务)
|
|
389
|
+
if @args_media_flag
|
|
379
390
|
media_upload_task = Pindo::TaskSystem::JPSUploadMediaTask.new(
|
|
380
391
|
[], # 空数组,自动从 JPSMedia/ 目录查找
|
|
381
392
|
config[:project_path], # upload_path
|
|
382
393
|
app_info_obj: git_app_info_obj,
|
|
383
394
|
workflow_info: git_workflow_info,
|
|
384
|
-
project_name: nil
|
|
395
|
+
project_name: nil,
|
|
396
|
+
required: @options[:media] || false # 仅用户显式 --media 时,找不到文件才算失败
|
|
385
397
|
)
|
|
386
398
|
# 依赖 Git 提交任务
|
|
387
399
|
media_upload_task.dependencies << git_commit_task.id
|
|
400
|
+
# 同样依赖 GitTagTask:并发模式下媒体上传可能与 build/tag 并行,
|
|
401
|
+
# 不依赖它就会关联到构建前的 commit,与包绑定的 commit 不一致
|
|
402
|
+
media_upload_task.dependencies << git_tag_task.id if git_tag_task
|
|
388
403
|
tasks << media_upload_task
|
|
389
404
|
end
|
|
390
405
|
|
|
391
|
-
#
|
|
406
|
+
# 10. 创建 Git Commit 绑定任务(如果需要,依赖上传任务)
|
|
392
407
|
bind_package_task = nil # 声明变量以便后续工作流消息任务使用
|
|
393
408
|
if @args_bind_flag
|
|
394
409
|
bind_package_task = Pindo::TaskSystem::JPSBindPackageTask.new(
|
|
395
410
|
nil, # app_version_list 为 nil,从依赖任务获取
|
|
396
411
|
project_dir: config[:project_path],
|
|
397
|
-
app_info_obj:
|
|
398
|
-
workflow_info:
|
|
412
|
+
app_info_obj: git_app_info_obj, # 使用 Git app_info_obj
|
|
413
|
+
workflow_info: git_workflow_info, # 使用 Git workflow_info
|
|
399
414
|
project_name: nil
|
|
400
415
|
)
|
|
401
|
-
# 依赖上传任务和 Git
|
|
416
|
+
# 依赖上传任务和 Git 任务
|
|
417
|
+
# GitTagTask 会提交构建注入文件并移动 HEAD,必须依赖它才能拿到 tag 所在的 commit
|
|
402
418
|
bind_package_task.dependencies << upload_task.id
|
|
403
419
|
bind_package_task.dependencies << git_commit_task.id
|
|
420
|
+
bind_package_task.dependencies << git_tag_task.id if git_tag_task
|
|
404
421
|
tasks << bind_package_task
|
|
405
422
|
end
|
|
406
423
|
|
|
407
|
-
#
|
|
424
|
+
# 11. 创建工作流消息任务(如果需要,发送到测试群)
|
|
408
425
|
if @args_send_flag
|
|
409
|
-
# 获取 Git 工作流信息
|
|
410
|
-
git_app_info_obj, git_workflow_info = PgyerHelper.share_instace.prepare_upload(
|
|
411
|
-
working_directory: config[:project_path],
|
|
412
|
-
conf: @args_conf,
|
|
413
|
-
package_type: nil,
|
|
414
|
-
manage_type: "git"
|
|
415
|
-
)
|
|
416
|
-
|
|
417
426
|
workflow_message_task = Pindo::TaskSystem::JPSWorkFlowMessageTask.new(
|
|
418
427
|
project_id: git_app_info_obj["id"],
|
|
419
|
-
workflow_id: git_workflow_info["id"
|
|
420
|
-
branch
|
|
428
|
+
workflow_id: git_workflow_info[:workflow_id], # workflow_info 是 symbol key 结构,没有 "id" 键
|
|
429
|
+
# branch 不传:由任务从 Git 依赖任务取 resolve 之后的真实发布分支
|
|
421
430
|
single: true,
|
|
422
431
|
app_info_obj: git_app_info_obj,
|
|
423
432
|
workflow_info: git_workflow_info
|
|
@@ -198,8 +198,6 @@ module Pindo
|
|
|
198
198
|
|
|
199
199
|
puts "package_type #{package_type} manage_type: #{manage_type}"
|
|
200
200
|
|
|
201
|
-
Funlog.instance.fancyinfo_success("获取工作流列表成功,共 #{workflows.size} 个工作流")
|
|
202
|
-
|
|
203
201
|
# 2. 根据 manage_type 或 package_type 过滤工作流
|
|
204
202
|
if manage_type == "git"
|
|
205
203
|
# manage_type 为 git 时,只筛选 manage_type == "git" 的工作流,不看 package_type
|
|
@@ -249,6 +247,10 @@ module Pindo
|
|
|
249
247
|
display_workflows = filtered_workflows
|
|
250
248
|
end
|
|
251
249
|
|
|
250
|
+
# 过滤后再报数:只报总数会让人以为剩下的工作流被漏掉了,
|
|
251
|
+
# 实际是按 manage_type / package_type 筛掉的,两个数字一起给出才不歧义
|
|
252
|
+
Funlog.instance.fancyinfo_success("获取工作流列表成功,共 #{workflows.size} 个工作流,其中 #{type_desc} #{display_workflows.size} 个")
|
|
253
|
+
|
|
252
254
|
# 2.5 若指定了 workflow_name,按名称精确匹配(忽略大小写与首尾空格)确定性选择。
|
|
253
255
|
# 只接受完整精确匹配,不做子串模糊匹配,避免 "Production" 误命中 "Legacy Production Upload"。
|
|
254
256
|
if workflow_name && !workflow_name.to_s.strip.empty? && !display_workflows.empty?
|
|
@@ -849,6 +851,16 @@ module Pindo
|
|
|
849
851
|
|
|
850
852
|
# 计算上传耗时
|
|
851
853
|
upload_duration = Time.now - upload_start_time
|
|
854
|
+
|
|
855
|
+
# upload_file 失败时返回 nil。不在这里拦住的话,后面会照常打印「上传完成」
|
|
856
|
+
# 和一个拿完整文件大小除以失败耗时算出来的假速度,再去做无谓的附件上传,
|
|
857
|
+
# 直到提交包信息前才失败——日志里先 ❌ 后 ✅ 就是这么来的。
|
|
858
|
+
if upload_res.nil?
|
|
859
|
+
Funlog.instance.fancyinfo_error("文件上传失败! 耗时: #{upload_duration.round(2)} 秒")
|
|
860
|
+
puts " 失败原因见上方日志;加 --verbose 重跑可看到接口返回的 code/msg"
|
|
861
|
+
raise Informative, "上传失败!"
|
|
862
|
+
end
|
|
863
|
+
|
|
852
864
|
upload_speed = file_size_mb / upload_duration
|
|
853
865
|
puts "✅ 文件上传完成! 耗时: #{upload_duration.round(2)} 秒, 平均速度: #{upload_speed.round(2)} MB/s"
|
|
854
866
|
|
|
@@ -865,8 +877,15 @@ module Pindo
|
|
|
865
877
|
|
|
866
878
|
# 计算附件上传耗时
|
|
867
879
|
attach_duration = Time.now - attach_start_time
|
|
868
|
-
|
|
869
|
-
|
|
880
|
+
|
|
881
|
+
# 同主文件:nil 即失败,不能照打「上传完成」。
|
|
882
|
+
# 但附件失败不阻断主包流程(下方 rescue 也是这个取向),只如实报告。
|
|
883
|
+
if attach_key_url.nil?
|
|
884
|
+
Funlog.instance.fancyinfo_warning("附件上传失败! 耗时: #{attach_duration.round(2)} 秒(不影响主包上传)")
|
|
885
|
+
else
|
|
886
|
+
attach_speed = attach_size_mb / attach_duration
|
|
887
|
+
puts "✅ 附件上传完成! 耗时: #{attach_duration.round(2)} 秒, 平均速度: #{attach_speed.round(2)} MB/s"
|
|
888
|
+
end
|
|
870
889
|
end
|
|
871
890
|
|
|
872
891
|
if !attach_key_url.nil?
|
|
@@ -1780,71 +1799,138 @@ module Pindo
|
|
|
1780
1799
|
|
|
1781
1800
|
# 获取特定 commit 已绑定的包 ID
|
|
1782
1801
|
#
|
|
1802
|
+
# 数据源是 commit_log/preview 的 bindVersions。
|
|
1803
|
+
#
|
|
1804
|
+
# 不能用 project_package/bind_list:它按 projectId 查、作用域看似更宽,
|
|
1805
|
+
# 但实测(项目 930 条记录)每条的 commitId、branch、workflowId、commitLogs
|
|
1806
|
+
# 全部为 nil——该接口只返回包本身,不携带 commit 绑定关系,
|
|
1807
|
+
# 按 commitId 过滤会恒得空列表,进而让覆盖式写入误删该 commit 的已有绑定。
|
|
1808
|
+
#
|
|
1809
|
+
# preview 需要传 workflowId,但实测同项目下不同 workflowId(3457 / 2650)
|
|
1810
|
+
# 返回的 bindVersions 完全一致——绑定按 commitId 全局记录,
|
|
1811
|
+
# 不存在"按工作流查漏、覆盖时被删掉"的问题。
|
|
1812
|
+
#
|
|
1813
|
+
# 绑定接口是覆盖式写入,调用方需要把已绑定的包一起提交,因此必须区分
|
|
1814
|
+
# 「确认没有绑定过」和「查不出来」——后者返回空数组会导致已有绑定被静默覆盖丢失。
|
|
1815
|
+
#
|
|
1783
1816
|
# @param commit_id [String] Git commit SHA(必需)
|
|
1784
|
-
# @param workflow_id [Integer, String] 工作流 ID
|
|
1785
|
-
# @return [Array<String
|
|
1817
|
+
# @param workflow_id [Integer, String] 工作流 ID(必需,接口入参)
|
|
1818
|
+
# @return [Array<String>, nil] 已绑定的包 ID 数组;查询失败或结构异常时返回 nil
|
|
1786
1819
|
def get_commit_bound_package_ids(commit_id:, workflow_id:)
|
|
1787
|
-
|
|
1788
|
-
|
|
1820
|
+
if commit_id.nil? || commit_id.empty?
|
|
1821
|
+
Funlog.instance.fancyinfo_warning("commit_id 为空,无法查询已绑定的包")
|
|
1822
|
+
return nil
|
|
1823
|
+
end
|
|
1824
|
+
|
|
1825
|
+
if workflow_id.nil? || workflow_id.to_s.empty?
|
|
1826
|
+
Funlog.instance.fancyinfo_warning("workflow_id 为空,无法查询已绑定的包")
|
|
1827
|
+
return nil
|
|
1828
|
+
end
|
|
1789
1829
|
|
|
1790
1830
|
begin
|
|
1791
|
-
# 使用 commit_log/preview API 直接查询特定 commit
|
|
1792
1831
|
result = @pgyer_client.get_commit_log_preview(
|
|
1793
1832
|
workflowId: workflow_id,
|
|
1794
1833
|
commitIds: [commit_id],
|
|
1795
|
-
params: { onlyCliff: false }
|
|
1834
|
+
params: { onlyCliff: false }
|
|
1796
1835
|
)
|
|
1797
1836
|
|
|
1798
1837
|
# 兼容两种响应格式
|
|
1799
1838
|
response_code = result&.dig("code") || result&.dig("meta", "code")
|
|
1800
1839
|
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
#
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1840
|
+
unless result && (response_code == 0 || response_code == 200)
|
|
1841
|
+
error_msg = result&.dig("msg") || result&.dig("meta", "message") || "未知错误"
|
|
1842
|
+
Funlog.instance.fancyinfo_warning("查询 Commit #{commit_id[0..7]} 的绑定信息失败: #{error_msg}")
|
|
1843
|
+
return nil
|
|
1844
|
+
end
|
|
1845
|
+
|
|
1846
|
+
data = result&.dig("data")
|
|
1847
|
+
|
|
1848
|
+
# code=0 且 data=nil 是接口表达「没有这条 commit」的正常响应(实测确认),
|
|
1849
|
+
# 不是畸形响应。此时该 commit 还没进 commit log,不可能有已记录的绑定。
|
|
1850
|
+
# 若误判为 nil,首次绑定(commit log 尚未生成)会被整体阻断。
|
|
1851
|
+
if data.nil?
|
|
1852
|
+
puts "[PINDO_DEBUG] Commit #{commit_id[0..7]} 不在 commit log 中,视为未绑定" if ENV['PINDO_DEBUG']
|
|
1853
|
+
return []
|
|
1854
|
+
end
|
|
1855
|
+
|
|
1856
|
+
list = data.is_a?(Array) ? data : [data]
|
|
1857
|
+
matched = list.select { |item| item.is_a?(Hash) && same_commit?(item["commitId"], commit_id) }
|
|
1858
|
+
|
|
1859
|
+
# 接口正常返回但没有这条 commit:该 commit 还没进 commit log,
|
|
1860
|
+
# 也就不可能有已记录的绑定
|
|
1861
|
+
if matched.empty?
|
|
1862
|
+
puts "[PINDO_DEBUG] Commit #{commit_id[0..7]} 不在 commit log 中,视为未绑定" if ENV['PINDO_DEBUG']
|
|
1863
|
+
return []
|
|
1864
|
+
end
|
|
1865
|
+
|
|
1866
|
+
# 同一个 commitId 在 commit log 里可能对应多条记录(push 一条、tag 一条,
|
|
1867
|
+
# 实测 commit_log/list 可见),哪条带 bindVersions 没有契约保证。
|
|
1868
|
+
# 只取第一条匹配会漏读绑定,进而让覆盖式写入删掉已有绑定,
|
|
1869
|
+
# 因此合并所有匹配记录的绑定。
|
|
1870
|
+
package_ids = []
|
|
1871
|
+
matched.each do |commit_info|
|
|
1872
|
+
bind_versions = commit_info["bindVersions"]
|
|
1873
|
+
|
|
1874
|
+
# 该记录没有绑定信息:未绑定的 commit 就是 null,属正常情况
|
|
1875
|
+
next if bind_versions.nil?
|
|
1876
|
+
|
|
1877
|
+
unless bind_versions.is_a?(Hash)
|
|
1878
|
+
Funlog.instance.fancyinfo_warning("bindVersions 结构异常(#{bind_versions.class}),无法确认已有绑定")
|
|
1879
|
+
return nil
|
|
1880
|
+
end
|
|
1881
|
+
|
|
1882
|
+
# bindVersions 形如 { "ipa" => { "projectPackageId" => "..." }, ... },
|
|
1883
|
+
# 每个平台一个包
|
|
1884
|
+
bind_versions.each do |platform, version_info|
|
|
1885
|
+
next if version_info.nil?
|
|
1886
|
+
|
|
1887
|
+
unless version_info.is_a?(Hash)
|
|
1888
|
+
Funlog.instance.fancyinfo_warning("bindVersions[#{platform}] 结构异常(#{version_info.class}),无法确认已有绑定")
|
|
1889
|
+
return nil
|
|
1820
1890
|
end
|
|
1821
1891
|
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
if
|
|
1826
|
-
|
|
1892
|
+
# 有平台条目却拿不到包 id:静默跳过会得到残缺列表,
|
|
1893
|
+
# 覆盖写入时等于把那个平台的绑定删掉
|
|
1894
|
+
package_id = version_info["projectPackageId"]
|
|
1895
|
+
if package_id.nil? || package_id.to_s.strip.empty?
|
|
1896
|
+
Funlog.instance.fancyinfo_warning("Commit #{commit_id[0..7]} 的 #{platform} 绑定缺少 projectPackageId,无法确认已有绑定")
|
|
1897
|
+
return nil
|
|
1827
1898
|
end
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
else
|
|
1831
|
-
# 如果获取失败,返回空数组(不阻止绑定流程)
|
|
1832
|
-
if ENV['PINDO_DEBUG']
|
|
1833
|
-
error_msg = result&.dig("msg") || result&.dig("meta", "message") || "未知错误"
|
|
1834
|
-
puts "[PINDO_DEBUG] 获取 commit 绑定包失败: #{error_msg}"
|
|
1899
|
+
|
|
1900
|
+
package_ids << package_id
|
|
1835
1901
|
end
|
|
1836
|
-
return []
|
|
1837
1902
|
end
|
|
1903
|
+
|
|
1904
|
+
puts "[PINDO_DEBUG] Commit #{commit_id[0..7]} 已绑定 #{package_ids.size} 个包: #{package_ids.inspect}" if ENV['PINDO_DEBUG']
|
|
1905
|
+
package_ids.uniq
|
|
1838
1906
|
rescue => e
|
|
1839
|
-
#
|
|
1840
|
-
if ENV['PINDO_DEBUG']
|
|
1841
|
-
|
|
1842
|
-
puts "[PINDO_DEBUG] Backtrace: #{e.backtrace[0..2].join("\n")}"
|
|
1843
|
-
end
|
|
1844
|
-
return []
|
|
1907
|
+
Funlog.instance.fancyinfo_warning("查询 commit 已绑定的包异常: #{e.message}")
|
|
1908
|
+
puts "[PINDO_DEBUG] Backtrace: #{e.backtrace[0..2].join("\n")}" if ENV['PINDO_DEBUG']
|
|
1909
|
+
return nil
|
|
1845
1910
|
end
|
|
1846
1911
|
end
|
|
1847
1912
|
|
|
1913
|
+
# 判断两个 commit SHA 是否指向同一个提交
|
|
1914
|
+
#
|
|
1915
|
+
# 一端是全长 40 位 SHA、另一端是短 SHA(或大小写不同)时,严格 == 会永不命中。
|
|
1916
|
+
# 对覆盖式写入的 bind_commit 来说这不是「查不到」而是「查成空」,
|
|
1917
|
+
# 会把该 commit 上已有的绑定一起删掉,因此按前缀 + 忽略大小写比对。
|
|
1918
|
+
# 要求较短的一方至少 7 字符,避免过短或异常值产生误匹配。
|
|
1919
|
+
#
|
|
1920
|
+
# @param sha_a [String, nil] 待比较的 SHA
|
|
1921
|
+
# @param sha_b [String, nil] 待比较的 SHA
|
|
1922
|
+
# @return [Boolean] 是否同一个提交
|
|
1923
|
+
def same_commit?(sha_a, sha_b)
|
|
1924
|
+
a = sha_a.to_s.strip.downcase
|
|
1925
|
+
b = sha_b.to_s.strip.downcase
|
|
1926
|
+
return false if a.empty? || b.empty?
|
|
1927
|
+
|
|
1928
|
+
shorter, longer = a.length <= b.length ? [a, b] : [b, a]
|
|
1929
|
+
return false if shorter.length < 7
|
|
1930
|
+
|
|
1931
|
+
longer.start_with?(shorter)
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1848
1934
|
# 获取工作流中已绑定的包 ID(已废弃,请使用 get_commit_bound_package_ids)
|
|
1849
1935
|
#
|
|
1850
1936
|
# @deprecated 使用 get_commit_bound_package_ids(commit_id:, workflow_id:) 替代
|
|
@@ -1984,10 +2070,11 @@ module Pindo
|
|
|
1984
2070
|
# @param project_id [String] 项目 ID
|
|
1985
2071
|
# @param workflow_id [Integer] 工作流 ID
|
|
1986
2072
|
# @param commit_id [String] Git commit SHA
|
|
1987
|
-
# @param branch [String]
|
|
2073
|
+
# @param branch [String, nil] 分支名(可选,nil 时不发送分支字段——传错的分支名
|
|
2074
|
+
# 会让 commit 与分支错误关联,比不传更糟)
|
|
1988
2075
|
# @param single [Boolean] 是否单个提交(可选,默认 true)
|
|
1989
2076
|
# @return [Hash] 发送结果
|
|
1990
|
-
def send_workflow_message(project_id:, workflow_id:, commit_id:, branch:
|
|
2077
|
+
def send_workflow_message(project_id:, workflow_id:, commit_id:, branch: nil, single: true)
|
|
1991
2078
|
if project_id.nil? || project_id.empty?
|
|
1992
2079
|
Funlog.instance.fancyinfo_error("project_id 不能为空")
|
|
1993
2080
|
return { success: false, error: "project_id 不能为空" }
|
|
@@ -2009,9 +2096,10 @@ module Pindo
|
|
|
2009
2096
|
workflowId: workflow_id,
|
|
2010
2097
|
params: {
|
|
2011
2098
|
single: single,
|
|
2099
|
+
# jpsclient 内部归一化为服务端要求的 branches 数组;nil 时不带该字段
|
|
2012
2100
|
branch: branch,
|
|
2013
2101
|
commitIds: [commit_id]
|
|
2014
|
-
}
|
|
2102
|
+
}.compact
|
|
2015
2103
|
)
|
|
2016
2104
|
|
|
2017
2105
|
# 兼容两种响应格式
|
|
@@ -26,6 +26,12 @@ module Pindo
|
|
|
26
26
|
'**/src/main/res'
|
|
27
27
|
].freeze
|
|
28
28
|
|
|
29
|
+
# Unity 工程判定即要求该文件存在(BuildHelper#unity_project?),故用精确路径而非 glob,
|
|
30
|
+
# 避免匹配到 Packages 下嵌入工程里的同名副本。
|
|
31
|
+
UNITY_PATTERNS = [
|
|
32
|
+
'ProjectSettings/ProjectSettings.asset'
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
29
35
|
EXCLUDED_PATH_COMPONENTS = %w[
|
|
30
36
|
.git
|
|
31
37
|
.gradle
|
|
@@ -56,9 +62,12 @@ module Pindo
|
|
|
56
62
|
source_paths(project_path, ANDROID_PATTERNS)
|
|
57
63
|
end
|
|
58
64
|
|
|
59
|
-
#
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
# 导出的平台工程落在已忽略的 GoodPlatform 里,不需要提交。
|
|
66
|
+
# 但 ProjectSettings.asset 是 Unity 源码配置,构建期间会被 Unity 写入
|
|
67
|
+
# (版本号、编译宏等),性质与 iOS 的 project.pbxproj / Info.plist 相同,
|
|
68
|
+
# 不提交就会在构建后残留为未提交改动,且 tag 上拿不到构建实际用的配置。
|
|
69
|
+
def unity(project_path)
|
|
70
|
+
source_paths(project_path, UNITY_PATTERNS)
|
|
62
71
|
end
|
|
63
72
|
|
|
64
73
|
private
|
|
@@ -122,6 +122,12 @@ module Pindo
|
|
|
122
122
|
# skip_without_tag 模式:跳过所有 git 同步操作,直接返回
|
|
123
123
|
if @process_type == Pindo::UncommittedFilesProcessType::SKIP_WITHOUT_TAG
|
|
124
124
|
coding_branch = get_current_branch_name
|
|
125
|
+
# 该模式不合并分支,代码就停在当前分支上,随 task_param 传给工作流消息任务的
|
|
126
|
+
# 分支必须是当前分支——用默认的 master 或探测出的发布分支,会发出
|
|
127
|
+
# 「feature 分支的 commit + master 分支名」这种自相矛盾的组合。
|
|
128
|
+
# detached HEAD 时取不到分支名(current_branch_name 返回 nil),保持 nil,
|
|
129
|
+
# 让下游工作流消息不带分支发送,而不是把字面量 "HEAD" 当成分支名。
|
|
130
|
+
@release_branch = Pindo::GitHandler.current_branch_name(local_repo_dir: root_dir)
|
|
125
131
|
@build_number, @commit_hash = git_repo_helper.get_build_number_from_commit(project_dir: root_dir)
|
|
126
132
|
|
|
127
133
|
# 版本号仍按正常优先级计算,仅"不打 tag / 不升版本",避免硬编码 0.0.0 污染 build.gradle 与下游上传参数
|
|
@@ -78,13 +78,19 @@ module Pindo
|
|
|
78
78
|
|
|
79
79
|
# 4. 创建并推送 Tag
|
|
80
80
|
tag_name = "#{@tag_pre}#{@build_version}"
|
|
81
|
-
git_repo_helper.create_and_push_tag(
|
|
81
|
+
tag_result = git_repo_helper.create_and_push_tag(
|
|
82
82
|
project_dir: root_dir,
|
|
83
83
|
tag_name: tag_name,
|
|
84
84
|
tag_type: @tag_type
|
|
85
85
|
)
|
|
86
|
+
|
|
87
|
+
# 5. 固化 commit 快照:commit_build_changes 与分支合并都可能移动 HEAD,
|
|
88
|
+
# 下游绑定/消息任务必须拿到「tag 这一刻」的 commit,而不是它们读取时的 HEAD
|
|
89
|
+
capture_git_commit_info
|
|
90
|
+
|
|
91
|
+
tag_result
|
|
86
92
|
ensure
|
|
87
|
-
#
|
|
93
|
+
# 6. 还原 stash
|
|
88
94
|
restore_stash(root_dir, stash_name) if stash_saved
|
|
89
95
|
end
|
|
90
96
|
end
|
|
@@ -25,6 +25,9 @@ module Pindo
|
|
|
25
25
|
@build_number = nil
|
|
26
26
|
@commit_hash = nil
|
|
27
27
|
|
|
28
|
+
# commit 信息快照(由子类在 do_work 中调用 capture_git_commit_info 固化)
|
|
29
|
+
@git_commit_info = nil
|
|
30
|
+
|
|
28
31
|
# 通过 project_path 获取 git_root_path
|
|
29
32
|
@git_root_path = @project_path ? Pindo::GitHandler.git_root_directory(local_repo_dir: @project_path) : nil
|
|
30
33
|
|
|
@@ -91,6 +94,24 @@ module Pindo
|
|
|
91
94
|
Pindo::GitHandler.git!(%W(-C #{@git_root_path} rev-parse --abbrev-ref HEAD)).strip
|
|
92
95
|
end
|
|
93
96
|
|
|
97
|
+
# 固化当前 HEAD 的 commit 信息快照
|
|
98
|
+
#
|
|
99
|
+
# build_task_param 默认在被读取时才去读 HEAD,若期间有其它任务移动了 HEAD
|
|
100
|
+
# (例如 GitTagTask 会提交构建注入文件),不同时刻读到的 commit 就不一致。
|
|
101
|
+
# 子类在 do_work 中调用本方法,即可把「任务完成那一刻」的 commit 固定下来。
|
|
102
|
+
def capture_git_commit_info
|
|
103
|
+
return unless @git_root_path
|
|
104
|
+
|
|
105
|
+
# 传入任务自身的 tag 前缀,自定义 --tag_pre 时才能正确识别 HEAD 上的版本 tag
|
|
106
|
+
info = Pindo::GitHandler.get_latest_conventional_commit(
|
|
107
|
+
project_dir: @git_root_path,
|
|
108
|
+
tag_prefix: @tag_pre
|
|
109
|
+
)
|
|
110
|
+
@git_commit_info = info if info && info[:commit_id]
|
|
111
|
+
rescue => e
|
|
112
|
+
Funlog.instance.fancyinfo_warning("固化 git commit 信息失败: #{e.message}")
|
|
113
|
+
end
|
|
114
|
+
|
|
94
115
|
# 构建任务参数(供其他任务使用)
|
|
95
116
|
def build_task_param
|
|
96
117
|
return {} unless @status == TaskStatus::SUCCESS
|
|
@@ -110,8 +131,12 @@ module Pindo
|
|
|
110
131
|
# 添加 git commit 信息(供 JPSUploadMediaTask 等任务使用)
|
|
111
132
|
if @git_root_path
|
|
112
133
|
begin
|
|
113
|
-
#
|
|
114
|
-
git_commit_info =
|
|
134
|
+
# 优先使用任务内固化的快照;没有快照时回退到读取当前 HEAD
|
|
135
|
+
git_commit_info = @git_commit_info ||
|
|
136
|
+
Pindo::GitHandler.get_latest_conventional_commit(
|
|
137
|
+
project_dir: @git_root_path,
|
|
138
|
+
tag_prefix: @tag_pre
|
|
139
|
+
)
|
|
115
140
|
if git_commit_info
|
|
116
141
|
param[:git_commit_id] = git_commit_info[:commit_id]
|
|
117
142
|
param[:git_commit_time] = git_commit_info[:commit_time]
|
|
@@ -27,8 +27,9 @@ module Pindo
|
|
|
27
27
|
# @option options [String] :git_commit_time Git commit 时间(可选)
|
|
28
28
|
# @option options [String] :git_commit_desc Git commit 描述(可选)
|
|
29
29
|
# @option options [String] :project_dir 项目目录(可选,用于自动获取 commit 信息)
|
|
30
|
-
# @option options [Hash] :app_info_obj JPS
|
|
31
|
-
# @option options [Hash] :workflow_info
|
|
30
|
+
# @option options [Hash] :app_info_obj JPS 应用信息对象(可选,继承自基类,本任务不使用)
|
|
31
|
+
# @option options [Hash] :workflow_info 工作流信息(必需,用于取 workflow_id;
|
|
32
|
+
# 回读绑定走 commit_log/preview,该接口以 workflowId 为入参)
|
|
32
33
|
# @option options [String] :project_name 项目名称(可选,继承自基类)
|
|
33
34
|
def initialize(app_version_list = nil, options = {})
|
|
34
35
|
# 兼容性处理:如果传入的是单个 Hash,转为数组
|
|
@@ -48,6 +49,11 @@ module Pindo
|
|
|
48
49
|
# 设置任务优先级为 LOW,确保在上传任务之后执行
|
|
49
50
|
options[:priority] ||= TaskPriority::LOW
|
|
50
51
|
|
|
52
|
+
# 重试延迟加随机抖动:绑定是「读取 → 合并 → 覆盖」,两个进程冲突后若都按固定
|
|
53
|
+
# 延迟重试,会在同一时刻再次相撞。抖动只降低碰撞概率,消除不了竞态——
|
|
54
|
+
# 根治需要服务端提供原子追加或 CAS(见 do_work 里的说明)。
|
|
55
|
+
options[:retry_delay] ||= self.class.default_retry_delay + rand(0..4)
|
|
56
|
+
|
|
51
57
|
super("绑定 包到Git工作流", options)
|
|
52
58
|
end
|
|
53
59
|
|
|
@@ -136,8 +142,10 @@ module Pindo
|
|
|
136
142
|
raise "无法登录 JPS,请检查配置"
|
|
137
143
|
end
|
|
138
144
|
|
|
139
|
-
# 6. 获取工作流 ID
|
|
140
|
-
|
|
145
|
+
# 6. 获取工作流 ID(commit_log/preview 的入参;绑定本身按 commitId 全局记录,
|
|
146
|
+
# 同项目下任一 workflowId 查到的 bindVersions 都相同)
|
|
147
|
+
workflow_id = @workflow_info&.dig(:workflow_id) || @workflow_info&.dig('workflow_id') ||
|
|
148
|
+
@workflow_info&.dig(:id) || @workflow_info&.dig('id')
|
|
141
149
|
unless workflow_id
|
|
142
150
|
raise "缺少 workflow_info,无法获取 workflow_id"
|
|
143
151
|
end
|
|
@@ -148,6 +156,12 @@ module Pindo
|
|
|
148
156
|
workflow_id: workflow_id
|
|
149
157
|
)
|
|
150
158
|
|
|
159
|
+
# 查询失败(nil)时中止:绑定接口是覆盖式写入,带着不完整的列表提交
|
|
160
|
+
# 会把该 commit 上已绑定的其它平台包冲掉。宁可报错让用户重试或补绑。
|
|
161
|
+
if existing_bound_ids.nil?
|
|
162
|
+
raise "无法确认 Commit #{@git_commit_id[0..7]} 已绑定的包,为避免覆盖丢失已中止绑定,请重试"
|
|
163
|
+
end
|
|
164
|
+
|
|
151
165
|
if existing_bound_ids.any?
|
|
152
166
|
puts " 📋 当前 Commit 已绑定的包: #{existing_bound_ids.size} 个"
|
|
153
167
|
end
|
|
@@ -172,6 +186,20 @@ module Pindo
|
|
|
172
186
|
|
|
173
187
|
if bind_result[:success]
|
|
174
188
|
Funlog.instance.fancyinfo_success("绑定成功!")
|
|
189
|
+
|
|
190
|
+
# 10. 写后回读校验
|
|
191
|
+
#
|
|
192
|
+
# 已知限制:「查询 → 合并 → 覆盖」跨进程不是原子的,客户端消除不了这个竞态。
|
|
193
|
+
# bind_commit 的入参只有 {commitId, projectPackageIds},既没有 revision/CAS
|
|
194
|
+
# 也没有追加语义,同项目下的其它接口同样不提供(已核对全部 project_package/
|
|
195
|
+
# commit_log 接口)。因此本校验只能发现「本次写入的包在回读时不见了」,
|
|
196
|
+
# 发现不了「本次写入覆盖掉了别人刚加的包」——后者要等对方回读时才暴露。
|
|
197
|
+
#
|
|
198
|
+
# 根治需要服务端支持,二选一即可:
|
|
199
|
+
# 1) bind_commit 增加 append 语义(只追加不覆盖)
|
|
200
|
+
# 2) 返回并校验 revision,做乐观并发控制
|
|
201
|
+
verify_bound_packages(pgyer_helper, workflow_id, merged_package_ids)
|
|
202
|
+
|
|
175
203
|
puts ""
|
|
176
204
|
|
|
177
205
|
{
|
|
@@ -193,6 +221,35 @@ module Pindo
|
|
|
193
221
|
|
|
194
222
|
private
|
|
195
223
|
|
|
224
|
+
# 写后回读校验:确认期望绑定的包都在服务端的绑定列表里
|
|
225
|
+
#
|
|
226
|
+
# 查询失败时只告警不失败——包已经写进去了,回读失败不代表绑定失败。
|
|
227
|
+
# 只有确认「期望的包没在列表里」才判定为被并发覆盖,抛异常交给任务重试。
|
|
228
|
+
#
|
|
229
|
+
# @param pgyer_helper [PgyerHelper] 已登录的 helper
|
|
230
|
+
# @param workflow_id [Integer, String] 工作流 ID
|
|
231
|
+
# @param expected_ids [Array<String>] 本次写入的包 ID 列表
|
|
232
|
+
def verify_bound_packages(pgyer_helper, workflow_id, expected_ids)
|
|
233
|
+
actual_ids = pgyer_helper.get_commit_bound_package_ids(
|
|
234
|
+
commit_id: @git_commit_id,
|
|
235
|
+
workflow_id: workflow_id
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if actual_ids.nil?
|
|
239
|
+
Funlog.instance.fancyinfo_warning("绑定后回读校验未能完成,请到 JPS 确认绑定结果")
|
|
240
|
+
return
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
missing_ids = expected_ids - actual_ids
|
|
244
|
+
return if missing_ids.empty?
|
|
245
|
+
|
|
246
|
+
# 抛出后由任务的重试机制重新走「查询 → 合并 → 写入」,对两种成因都收敛:
|
|
247
|
+
# 并发覆盖时会重新读到对方的包并一起写回;服务端写后读延迟时下一次读到的即是新值。
|
|
248
|
+
raise "绑定结果校验失败:#{missing_ids.size} 个包未出现在绑定列表中" \
|
|
249
|
+
"(其它进程同时绑定覆盖了本次结果,或服务端写入尚未可见)," \
|
|
250
|
+
"缺失包 ID: #{missing_ids.join(', ')}"
|
|
251
|
+
end
|
|
252
|
+
|
|
196
253
|
# 从依赖任务获取 app_version_list
|
|
197
254
|
def fetch_app_version_from_dependencies
|
|
198
255
|
# 获取所有 JPSUploadTask 的数据(可能有多个平台的上传任务)
|
|
@@ -210,10 +267,8 @@ module Pindo
|
|
|
210
267
|
|
|
211
268
|
# 从依赖任务获取或自动获取 git commit 信息
|
|
212
269
|
def fetch_git_commit_info
|
|
213
|
-
# 1.
|
|
214
|
-
git_data =
|
|
215
|
-
# 2. 降级到 GitCommitTask
|
|
216
|
-
git_data = get_data_param_by_key(:git_commit) if git_data.nil? || git_data.empty?
|
|
270
|
+
# 1. 从依赖任务获取(优先 GitTagTask,降级 GitCommitTask)
|
|
271
|
+
git_data = git_commit_data_param
|
|
217
272
|
|
|
218
273
|
if git_data && git_data[:task_param]
|
|
219
274
|
param = git_data[:task_param]
|
|
@@ -222,7 +277,7 @@ module Pindo
|
|
|
222
277
|
@git_commit_desc = param[:git_commit_desc] if param[:git_commit_desc]
|
|
223
278
|
end
|
|
224
279
|
|
|
225
|
-
#
|
|
280
|
+
# 2. 如果依赖任务都没有提供,且指定了 project_dir,使用自动获取
|
|
226
281
|
if (@git_commit_id.nil? || @git_commit_id.empty?) && @project_dir
|
|
227
282
|
# 查找 git 仓库根目录
|
|
228
283
|
git_root = Pindo::GitHandler.git_root_directory(local_repo_dir: @project_dir)
|
|
@@ -33,12 +33,16 @@ module Pindo
|
|
|
33
33
|
# @option options [Hash] :app_info_obj JPS 应用信息对象(可选,继承自基类)
|
|
34
34
|
# @option options [Hash] :workflow_info 工作流信息(可选,继承自基类)
|
|
35
35
|
# @option options [String] :project_name 项目名称(可选,继承自基类)
|
|
36
|
+
# @option options [Boolean] :required 用户是否显式要求上传媒体(默认 false)。
|
|
37
|
+
# 为 true 时找不到媒体文件会让任务失败;--bind/--send 隐式带出的媒体上传保持
|
|
38
|
+
# 宽松,因为「项目里没有 JPSMedia 文件」是常态,不该让整条构建失败。
|
|
36
39
|
def initialize(file_paths, upload_path, options = {})
|
|
37
40
|
@file_paths = file_paths || [] # 要上传的文件路径列表
|
|
38
41
|
@upload_path = upload_path # 项目路径
|
|
39
42
|
@git_commit_id = options[:git_commit_id] # Git commit SHA
|
|
40
43
|
@git_commit_time = options[:git_commit_time] # Git commit 时间
|
|
41
44
|
@git_commit_desc = options[:git_commit_desc] # Git commit 描述
|
|
45
|
+
@required = options.fetch(:required, false) # 是否为用户显式要求
|
|
42
46
|
|
|
43
47
|
# 设置任务优先级为 LOW,确保在其他任务之后执行
|
|
44
48
|
options[:priority] ||= TaskPriority::LOW
|
|
@@ -97,10 +101,8 @@ module Pindo
|
|
|
97
101
|
|
|
98
102
|
# 2. 如果没有提供 git_commit_id,尝试从依赖任务获取或自动获取
|
|
99
103
|
if @git_commit_id.nil? || @git_commit_id.empty?
|
|
100
|
-
# 2.1
|
|
101
|
-
git_data =
|
|
102
|
-
# 2.2 降级到 GitCommitTask
|
|
103
|
-
git_data = get_data_param_by_key(:git_commit) if git_data.nil? || git_data.empty?
|
|
104
|
+
# 2.1 从依赖任务获取(优先 GitTagTask,降级 GitCommitTask)
|
|
105
|
+
git_data = git_commit_data_param
|
|
104
106
|
|
|
105
107
|
if git_data && git_data[:task_param]
|
|
106
108
|
param = git_data[:task_param]
|
|
@@ -110,7 +112,7 @@ module Pindo
|
|
|
110
112
|
@git_commit_desc = param[:git_commit_desc] if param[:git_commit_desc]
|
|
111
113
|
end
|
|
112
114
|
|
|
113
|
-
# 2.
|
|
115
|
+
# 2.2 如果依赖任务都没有提供,回退到读取当前仓库状态
|
|
114
116
|
if @git_commit_id.nil? || @git_commit_id.empty?
|
|
115
117
|
git_info = Pindo::GitHandler.get_latest_conventional_commit(project_dir: git_root)
|
|
116
118
|
@git_commit_id = git_info[:commit_id]
|
|
@@ -154,6 +156,13 @@ module Pindo
|
|
|
154
156
|
puts " ❌ 没有找到有效的 media 文件"
|
|
155
157
|
puts " 提示: 请在项目根目录创建 JPSMedia/ 目录并放入要上传的图片或视频文件"
|
|
156
158
|
puts ""
|
|
159
|
+
|
|
160
|
+
# 用户显式传了 --media 却没有文件可传:任务系统只看异常不看 result[:success],
|
|
161
|
+
# 这里不抛出的话命令会以 0 退出,等于悄悄没做用户要求的事
|
|
162
|
+
if @required
|
|
163
|
+
raise "没有找到有效的 media 文件;请在 JPSMedia/ 目录放入图片或视频后重试"
|
|
164
|
+
end
|
|
165
|
+
|
|
157
166
|
return {
|
|
158
167
|
success: false,
|
|
159
168
|
success_urls: [],
|