pindo 5.14.4 → 5.14.6
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 +140 -65
- data/lib/pindo/client/httpclient.rb +88 -12
- data/lib/pindo/command/android/autobuild.rb +100 -32
- data/lib/pindo/command/appstore/bundleid.rb +1 -1
- data/lib/pindo/command/appstore/pem.rb +1 -1
- data/lib/pindo/command/ios/autobuild.rb +116 -56
- data/lib/pindo/command/jps/apptest.rb +129 -50
- data/lib/pindo/command/jps/bind.rb +284 -121
- data/lib/pindo/command/jps/media.rb +1 -15
- data/lib/pindo/command/jps/resign.rb +109 -99
- data/lib/pindo/command/jps/upload.rb +31 -4
- data/lib/pindo/command/jps.rb +0 -1
- data/lib/pindo/command/unity/autobuild.rb +100 -39
- data/lib/pindo/command/web/autobuild.rb +95 -27
- data/lib/pindo/command.rb +23 -15
- data/lib/pindo/module/pgyer/pgyerhelper.rb +181 -0
- data/lib/pindo/module/task/model/git/git_commit_task.rb +55 -4
- data/lib/pindo/module/task/model/git/git_tag_task.rb +5 -4
- data/lib/pindo/module/task/model/jps/jps_bind_package_task.rb +233 -0
- data/lib/pindo/module/task/model/jps/jps_message_task.rb +9 -6
- data/lib/pindo/module/task/model/jps/jps_resign_task.rb +20 -21
- data/lib/pindo/module/task/model/jps/jps_upload_media_task.rb +57 -22
- data/lib/pindo/module/task/model/jps/jps_upload_task.rb +4 -4
- data/lib/pindo/module/task/model/jps/jps_workflow_message_task.rb +190 -0
- data/lib/pindo/options/core/option_configuration.rb +4 -36
- data/lib/pindo/options/core/option_initializer.rb +6 -3
- data/lib/pindo/options/core/option_item.rb +0 -3
- data/lib/pindo/options/groups/jps_options.rb +30 -10
- data/lib/pindo/version.rb +1 -1
- metadata +12 -37
- data/lib/pindo/command/jps/comment.rb +0 -84
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: da83c30dd943e6edfa9320b5944d43b76fd467c2ebdf1aff2f010a07235628a9
|
|
4
|
+
data.tar.gz: a05b5d981a1431cfc9c0659d20966f4eaafee7433de93d27ebddb11310a57678
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bf83411f15e4a91b3c80d5add990d84e6a00513deee5943304a0a5cb72a29d9495d8cbbd14da5e8463bd4345d2e778997e7947cb7bc681d4046e362eb7fadb1d
|
|
7
|
+
data.tar.gz: efee3ed4cf27cc7206f57543865397dc126d3c4e902451a59b617e2547fa8c5fae96330dcd9c9b9f3b2ddc12545024537fe46620199a3261a32da8afb1dc7902
|
|
@@ -859,98 +859,149 @@ module Pindo
|
|
|
859
859
|
|
|
860
860
|
|
|
861
861
|
|
|
862
|
-
#
|
|
862
|
+
# 合并分支
|
|
863
|
+
# 将源分支合并到目标分支,支持单向或双向同步
|
|
864
|
+
#
|
|
863
865
|
# @param project_dir [String] 项目目录
|
|
864
|
-
# @param
|
|
865
|
-
# @param
|
|
866
|
-
|
|
866
|
+
# @param source_branch [String] 源分支名称(要合并的分支)
|
|
867
|
+
# @param target_branch [String] 目标分支名称(接收合并的分支)
|
|
868
|
+
# @param sync_branches [Boolean] 是否双向合并(同步两分支),默认 false
|
|
869
|
+
# - true: 双向合并,source → target,然后 target → source(确保两分支完全同步)
|
|
870
|
+
# - false: 单向合并,仅 source → target
|
|
871
|
+
# @return [void]
|
|
872
|
+
def merge_branches(project_dir:, source_branch:, target_branch:, sync_branches: false)
|
|
867
873
|
current_project_dir = project_dir
|
|
868
|
-
Funlog.instance.fancyinfo_start("开始合并到#{
|
|
869
|
-
if !
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
if remote_branch_exists?(local_repo_dir: current_project_dir, branch:
|
|
874
|
-
Funlog.instance.fancyinfo_update("存在#{
|
|
875
|
-
if local_branch_exists?(local_repo_dir: current_project_dir, branch:
|
|
876
|
-
Funlog.instance.fancyinfo_update("存在#{
|
|
877
|
-
git!(%W(-C #{current_project_dir} checkout #{
|
|
874
|
+
Funlog.instance.fancyinfo_start("开始合并到#{target_branch}分支")
|
|
875
|
+
if !source_branch.eql?(target_branch)
|
|
876
|
+
source_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{source_branch})).strip
|
|
877
|
+
target_branch_commit_id = nil
|
|
878
|
+
|
|
879
|
+
if remote_branch_exists?(local_repo_dir: current_project_dir, branch: target_branch)
|
|
880
|
+
Funlog.instance.fancyinfo_update("存在#{target_branch}远程分支")
|
|
881
|
+
if local_branch_exists?(local_repo_dir: current_project_dir, branch: target_branch)
|
|
882
|
+
Funlog.instance.fancyinfo_update("存在#{target_branch}本地分支")
|
|
883
|
+
git!(%W(-C #{current_project_dir} checkout #{target_branch}))
|
|
878
884
|
else
|
|
879
|
-
Funlog.instance.fancyinfo_update("不存在#{
|
|
880
|
-
git!(%W(-C #{current_project_dir} checkout -b #{
|
|
885
|
+
Funlog.instance.fancyinfo_update("不存在#{target_branch}本地分支")
|
|
886
|
+
git!(%W(-C #{current_project_dir} checkout -b #{target_branch} origin/#{target_branch}))
|
|
881
887
|
end
|
|
882
888
|
|
|
883
|
-
git!(%W(-C #{current_project_dir} branch --set-upstream-to=origin/#{
|
|
884
|
-
git!(%W(-C #{current_project_dir} fetch origin #{
|
|
885
|
-
git!(%W(-C #{current_project_dir} merge origin/#{
|
|
889
|
+
git!(%W(-C #{current_project_dir} branch --set-upstream-to=origin/#{target_branch} #{target_branch}))
|
|
890
|
+
git!(%W(-C #{current_project_dir} fetch origin #{target_branch}))
|
|
891
|
+
git!(%W(-C #{current_project_dir} merge origin/#{target_branch}))
|
|
886
892
|
|
|
887
893
|
# 执行合并操作
|
|
888
|
-
Executable.capture_command('git', %W(-C #{current_project_dir} merge #{
|
|
894
|
+
Executable.capture_command('git', %W(-C #{current_project_dir} merge #{source_branch}), :capture => :out)
|
|
889
895
|
|
|
890
896
|
# 检查是否有冲突
|
|
891
897
|
conflict_filelist = git!(%W(-C #{current_project_dir} diff --name-only --diff-filter=U --relative))
|
|
892
898
|
if !conflict_filelist.nil? && !conflict_filelist.strip.empty?
|
|
893
|
-
raise Informative, "合并#{
|
|
899
|
+
raise Informative, "合并#{source_branch}到#{target_branch}时产生冲突,请手动处理!"
|
|
894
900
|
else
|
|
895
901
|
git!(%W(-C #{current_project_dir} push))
|
|
896
|
-
Funlog.instance.fancyinfo_success("代码已经合并到#{
|
|
897
|
-
# 获取
|
|
902
|
+
Funlog.instance.fancyinfo_success("代码已经合并到#{target_branch}分支")
|
|
903
|
+
# 获取 target_branch 的 commit ID(处理空分支情况)
|
|
898
904
|
begin
|
|
899
|
-
|
|
905
|
+
target_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{target_branch})).strip
|
|
900
906
|
rescue => e
|
|
901
|
-
# 分支可能存在但没有提交(空分支),此时使用
|
|
902
|
-
Funlog.instance.fancyinfo_update("#{
|
|
903
|
-
|
|
907
|
+
# 分支可能存在但没有提交(空分支),此时使用 source_branch 的 commit
|
|
908
|
+
Funlog.instance.fancyinfo_update("#{target_branch}分支为空或获取commit失败,将使用当前分支commit")
|
|
909
|
+
target_branch_commit_id = source_branch_commit_id
|
|
904
910
|
end
|
|
905
911
|
end
|
|
906
912
|
|
|
907
913
|
else
|
|
908
|
-
if local_branch_exists?(local_repo_dir: current_project_dir, branch:
|
|
909
|
-
Funlog.instance.fancyinfo_update("不存在#{
|
|
910
|
-
Funlog.instance.fancyinfo_update("存在#{
|
|
911
|
-
git!(%W(-C #{current_project_dir} checkout #{
|
|
914
|
+
if local_branch_exists?(local_repo_dir: current_project_dir, branch: target_branch)
|
|
915
|
+
Funlog.instance.fancyinfo_update("不存在#{target_branch}远程分支")
|
|
916
|
+
Funlog.instance.fancyinfo_update("存在#{target_branch}本地分支")
|
|
917
|
+
git!(%W(-C #{current_project_dir} checkout #{target_branch}))
|
|
912
918
|
# 使用带时间戳的备份分支名,避免重复操作时冲突
|
|
913
|
-
backup_branch = "#{
|
|
919
|
+
backup_branch = "#{target_branch}_backup_#{Time.now.strftime('%Y%m%d%H%M%S')}"
|
|
914
920
|
Funlog.instance.fancyinfo_update("备份本地分支到: #{backup_branch}")
|
|
915
921
|
git!(%W(-C #{current_project_dir} checkout -b #{backup_branch}))
|
|
916
|
-
git!(%W(-C #{current_project_dir} checkout #{
|
|
917
|
-
git!(%W(-C #{current_project_dir} branch -D #{
|
|
922
|
+
git!(%W(-C #{current_project_dir} checkout #{source_branch}))
|
|
923
|
+
git!(%W(-C #{current_project_dir} branch -D #{target_branch}))
|
|
918
924
|
else
|
|
919
|
-
Funlog.instance.fancyinfo_update("不存在#{
|
|
920
|
-
Funlog.instance.fancyinfo_update("不存在#{
|
|
925
|
+
Funlog.instance.fancyinfo_update("不存在#{target_branch}远程分支")
|
|
926
|
+
Funlog.instance.fancyinfo_update("不存在#{target_branch}本地分支")
|
|
921
927
|
end
|
|
922
928
|
|
|
923
|
-
|
|
924
|
-
git!(%W(-C #{current_project_dir}
|
|
925
|
-
git!(%W(-C #{current_project_dir}
|
|
929
|
+
# 基于 source_branch 创建 target_branch(明确指定起点,避免基于错误的分支创建)
|
|
930
|
+
git!(%W(-C #{current_project_dir} checkout -b #{target_branch} #{source_branch}))
|
|
931
|
+
git!(%W(-C #{current_project_dir} push origin #{target_branch}))
|
|
932
|
+
git!(%W(-C #{current_project_dir} branch --set-upstream-to=origin/#{target_branch} #{target_branch}))
|
|
926
933
|
|
|
927
|
-
Funlog.instance.fancyinfo_success("代码已经合并到#{
|
|
928
|
-
# 获取
|
|
934
|
+
Funlog.instance.fancyinfo_success("代码已经合并到#{target_branch}分支")
|
|
935
|
+
# 获取 target_branch 的 commit ID(处理空分支情况)
|
|
929
936
|
begin
|
|
930
|
-
|
|
937
|
+
target_branch_commit_id = git!(%W(-C #{current_project_dir} rev-parse #{target_branch})).strip
|
|
931
938
|
rescue => e
|
|
932
|
-
# 新创建的分支,commit ID 应该与
|
|
933
|
-
|
|
939
|
+
# 新创建的分支,commit ID 应该与 source_branch 相同
|
|
940
|
+
target_branch_commit_id = source_branch_commit_id
|
|
934
941
|
end
|
|
935
942
|
end
|
|
936
943
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
944
|
+
# 同步分支:将 source_branch 同步到 target_branch(确保两分支在同一节点)
|
|
945
|
+
git!(%W(-C #{current_project_dir} checkout #{source_branch}))
|
|
946
|
+
if sync_branches
|
|
947
|
+
if target_branch_commit_id && !target_branch_commit_id.eql?(source_branch_commit_id)
|
|
948
|
+
# 检查是否可以 fast-forward(即 source_branch 是 target_branch 的祖先)
|
|
949
|
+
is_ancestor = false
|
|
950
|
+
begin
|
|
951
|
+
git!(%W(-C #{current_project_dir} merge-base --is-ancestor #{source_branch} #{target_branch}))
|
|
952
|
+
is_ancestor = true
|
|
953
|
+
rescue => e
|
|
954
|
+
# 不是祖先关系,说明 source_branch 有独立提交(理论上不应该,因为刚合并过)
|
|
955
|
+
Funlog.instance.fancyinfo_warning("#{source_branch} 不是 #{target_branch} 的祖先")
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
if is_ancestor
|
|
959
|
+
# 可以安全 fast-forward(source 的所有提交都在 target 中)
|
|
960
|
+
Funlog.instance.fancyinfo_update("#{source_branch}是#{target_branch}的祖先,执行 fast-forward 合并")
|
|
961
|
+
begin
|
|
962
|
+
# 尝试 fast-forward only merge(确保不产生新 commit)
|
|
963
|
+
git!(%W(-C #{current_project_dir} merge --ff-only #{target_branch}))
|
|
964
|
+
Funlog.instance.fancyinfo_success("已将#{source_branch} fast-forward 到#{target_branch},两分支现在在同一节点")
|
|
965
|
+
|
|
966
|
+
# 推送到远程(普通 push,因为是 fast-forward)
|
|
967
|
+
git!(%W(-C #{current_project_dir} push origin #{source_branch}))
|
|
968
|
+
Funlog.instance.fancyinfo_success("已推送#{source_branch}分支到远程")
|
|
969
|
+
rescue => e
|
|
970
|
+
if e.message.include?("Not possible to fast-forward")
|
|
971
|
+
# 理论上不应该到这里,因为前面检查过是祖先
|
|
972
|
+
Funlog.instance.fancyinfo_warning("无法 fast-forward,将产生 merge commit")
|
|
973
|
+
git!(%W(-C #{current_project_dir} merge #{target_branch}))
|
|
974
|
+
git!(%W(-C #{current_project_dir} push origin #{source_branch}))
|
|
975
|
+
else
|
|
976
|
+
raise e
|
|
977
|
+
end
|
|
978
|
+
end
|
|
979
|
+
else
|
|
980
|
+
# 不是祖先关系,使用普通 merge(会产生新的 merge commit)
|
|
981
|
+
Funlog.instance.fancyinfo_warning("#{source_branch}不是#{target_branch}的祖先,将执行普通合并(可能产生新 commit)")
|
|
982
|
+
Executable.capture_command('git', %W(-C #{current_project_dir} merge #{target_branch}), :capture => :out)
|
|
983
|
+
|
|
984
|
+
# 检查冲突
|
|
985
|
+
conflict_filelist = git!(%W(-C #{current_project_dir} diff --name-only --diff-filter=U --relative))
|
|
986
|
+
if !conflict_filelist.nil? && !conflict_filelist.strip.empty?
|
|
987
|
+
raise Informative, "合并#{target_branch}到#{source_branch}时产生冲突,请手动处理!"
|
|
988
|
+
end
|
|
989
|
+
|
|
990
|
+
git!(%W(-C #{current_project_dir} push origin #{source_branch}))
|
|
991
|
+
Funlog.instance.fancyinfo_success("已将#{target_branch}合并到#{source_branch}(产生了新 merge commit)")
|
|
992
|
+
end
|
|
993
|
+
else
|
|
994
|
+
Funlog.instance.fancyinfo_success("#{source_branch}和#{target_branch}已经在同一节点,无需同步")
|
|
943
995
|
end
|
|
944
|
-
|
|
996
|
+
else
|
|
997
|
+
Funlog.instance.fancyinfo_success("单向合并完成,未同步 #{target_branch} 到 #{source_branch}")
|
|
945
998
|
end
|
|
946
|
-
git!(%W(-C #{current_project_dir} push origin #{coding_branch}))
|
|
947
|
-
Funlog.instance.fancyinfo_success("已推送#{coding_branch}分支到远程")
|
|
948
999
|
else
|
|
949
|
-
Funlog.instance.fancyinfo_success("代码处于#{
|
|
1000
|
+
Funlog.instance.fancyinfo_success("代码处于#{source_branch}分支,无需合并")
|
|
950
1001
|
end
|
|
951
1002
|
end
|
|
952
1003
|
|
|
953
|
-
#
|
|
1004
|
+
# 检查并推送未推送的本地提交,确保本地和远程分支完全同步
|
|
954
1005
|
# @param project_dir [String] 项目目录路径
|
|
955
1006
|
# @param branch [String] 分支名称
|
|
956
1007
|
# @return [void]
|
|
@@ -976,20 +1027,44 @@ module Pindo
|
|
|
976
1027
|
return
|
|
977
1028
|
end
|
|
978
1029
|
|
|
979
|
-
# 3.
|
|
1030
|
+
# 3. 先 fetch 获取最新的远程状态
|
|
1031
|
+
git!(%W(-C #{project_dir} fetch origin #{branch}))
|
|
1032
|
+
|
|
1033
|
+
# 4. 检查本地分支是否领先远程分支
|
|
980
1034
|
ahead_count = git!(%W(-C #{project_dir} rev-list --count #{remote_branch}..#{branch})).strip.to_i
|
|
981
1035
|
|
|
982
|
-
#
|
|
983
|
-
|
|
984
|
-
|
|
1036
|
+
# 5. 检查远程分支是否领先本地分支
|
|
1037
|
+
behind_count = git!(%W(-C #{project_dir} rev-list --count #{branch}..#{remote_branch})).strip.to_i
|
|
1038
|
+
|
|
1039
|
+
# 6. 根据同步状态执行相应操作
|
|
1040
|
+
if ahead_count == 0 && behind_count == 0
|
|
1041
|
+
Funlog.instance.fancyinfo_success("本地分支 #{branch} 与远程分支完全同步")
|
|
985
1042
|
return
|
|
986
|
-
|
|
1043
|
+
elsif ahead_count > 0 && behind_count == 0
|
|
1044
|
+
# 仅本地领先:直接推送
|
|
1045
|
+
Funlog.instance.fancyinfo_warning("检测到 #{ahead_count} 个本地提交尚未推送")
|
|
1046
|
+
Funlog.instance.fancyinfo_start("正在推送到远程分支 #{remote_branch}...")
|
|
1047
|
+
git!(%W(-C #{project_dir} push origin #{branch}))
|
|
1048
|
+
Funlog.instance.fancyinfo_success("推送成功!")
|
|
1049
|
+
elsif ahead_count == 0 && behind_count > 0
|
|
1050
|
+
# 仅远程领先:重置本地到远程位置
|
|
1051
|
+
Funlog.instance.fancyinfo_warning("远程分支领先本地 #{behind_count} 个提交")
|
|
1052
|
+
|
|
1053
|
+
# 检查工作目录是否干净
|
|
1054
|
+
status = git!(%W(-C #{project_dir} status --porcelain)).strip
|
|
1055
|
+
unless status.empty?
|
|
1056
|
+
raise Informative, "工作目录有未提交的修改,无法同步远程更新。请先提交或 stash 修改。"
|
|
1057
|
+
end
|
|
987
1058
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1059
|
+
# 工作目录干净,安全地重置到远程位置
|
|
1060
|
+
Funlog.instance.fancyinfo_start("正在重置本地分支到远程位置...")
|
|
1061
|
+
git!(%W(-C #{project_dir} reset --hard #{remote_branch}))
|
|
1062
|
+
Funlog.instance.fancyinfo_success("已同步到远程分支!")
|
|
1063
|
+
else
|
|
1064
|
+
# 分叉:需要合并
|
|
1065
|
+
Funlog.instance.fancyinfo_warning("本地和远程分支已分叉:本地领先 #{ahead_count} 个提交,远程领先 #{behind_count} 个提交")
|
|
1066
|
+
raise Informative, "本地分支和远程分支已分叉,请手动合并或变基后再继续!"
|
|
1067
|
+
end
|
|
993
1068
|
end
|
|
994
1069
|
|
|
995
1070
|
end
|
|
@@ -3,13 +3,80 @@ require 'uri'
|
|
|
3
3
|
require 'json'
|
|
4
4
|
require 'faraday'
|
|
5
5
|
require 'pindo/base/aeshelper'
|
|
6
|
-
require '
|
|
6
|
+
require 'typhoeus'
|
|
7
|
+
require 'typhoeus/adapters/faraday'
|
|
7
8
|
|
|
8
9
|
module Pindo
|
|
9
|
-
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# 简单的 Faraday 重试中间件(替代 faraday-retry)
|
|
12
|
+
class SimpleRetryMiddleware < Faraday::Middleware
|
|
13
|
+
# 默认幂等的 HTTP 方法(可安全重试)
|
|
14
|
+
IDEMPOTENT_METHODS = [:get, :head, :put, :delete, :options, :trace].freeze
|
|
15
|
+
# 可重试的 HTTP 状态码(5xx 服务器错误)
|
|
16
|
+
RETRIABLE_STATUS_CODES = (500..599).freeze
|
|
17
|
+
|
|
18
|
+
def initialize(app, options = {})
|
|
19
|
+
super(app)
|
|
20
|
+
@max = options[:max] || 3 # 最大重试次数(不包括首次尝试)
|
|
21
|
+
@interval = options[:interval] || 0.5
|
|
22
|
+
@backoff_factor = options[:backoff_factor] || 2
|
|
23
|
+
@interval_randomness = options[:interval_randomness] || 0.5
|
|
24
|
+
@exceptions = options[:exceptions] || [Faraday::TimeoutError, Faraday::ConnectionFailed]
|
|
25
|
+
@methods = options[:methods] || IDEMPOTENT_METHODS # 允许重试的 HTTP 方法
|
|
26
|
+
@retry_statuses = options[:retry_statuses] || RETRIABLE_STATUS_CODES
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def call(env)
|
|
30
|
+
retries = 0
|
|
31
|
+
|
|
32
|
+
loop do
|
|
33
|
+
begin
|
|
34
|
+
response = @app.call(env)
|
|
35
|
+
|
|
36
|
+
# 检查 HTTP 状态码是否需要重试(5xx 错误)
|
|
37
|
+
# 同时必须满足幂等性要求,避免非幂等请求(如 POST)被意外重试
|
|
38
|
+
if retriable_response?(response) && retriable_request?(env) && retries < @max
|
|
39
|
+
retries += 1
|
|
40
|
+
sleep_with_jitter(retries)
|
|
41
|
+
next # 继续下一次循环(重试)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
return response # 成功,返回响应
|
|
45
|
+
|
|
46
|
+
rescue *@exceptions => e
|
|
47
|
+
# 检查是否为幂等方法,非幂等方法不自动重试
|
|
48
|
+
if retriable_request?(env) && retries < @max
|
|
49
|
+
retries += 1
|
|
50
|
+
sleep_with_jitter(retries)
|
|
51
|
+
next # 继续下一次循环(重试)
|
|
52
|
+
else
|
|
53
|
+
raise e # 不能重试,抛出异常
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
12
60
|
|
|
61
|
+
# 检查请求是否可重试(幂等性检查)
|
|
62
|
+
def retriable_request?(env)
|
|
63
|
+
@methods.include?(env[:method])
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# 检查响应是否需要重试(5xx 状态码)
|
|
67
|
+
def retriable_response?(response)
|
|
68
|
+
@retry_statuses.include?(response.status)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# 指数退避 + 随机抖动
|
|
72
|
+
def sleep_with_jitter(retry_count)
|
|
73
|
+
sleep_time = @interval * (@backoff_factor ** (retry_count - 1))
|
|
74
|
+
jitter = rand * sleep_time * @interval_randomness
|
|
75
|
+
sleep(sleep_time + jitter)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
class HttpClient
|
|
13
80
|
|
|
14
81
|
attr_accessor :token
|
|
15
82
|
attr_accessor :baseurl
|
|
@@ -25,23 +92,32 @@ module Pindo
|
|
|
25
92
|
}
|
|
26
93
|
|
|
27
94
|
retry_options = {
|
|
28
|
-
max: 3,
|
|
29
|
-
interval: 0.5,
|
|
30
|
-
backoff_factor: 2,
|
|
31
|
-
interval_randomness: 0.5
|
|
95
|
+
max: 3,
|
|
96
|
+
interval: 0.5,
|
|
97
|
+
backoff_factor: 2,
|
|
98
|
+
interval_randomness: 0.5
|
|
32
99
|
}
|
|
33
100
|
|
|
34
101
|
con = Faraday.new do |config|
|
|
35
|
-
|
|
36
|
-
config.
|
|
102
|
+
# 使用自定义重试中间件
|
|
103
|
+
config.use SimpleRetryMiddleware, retry_options
|
|
104
|
+
# 使用 Typhoeus 适配器(支持代理和连接池)
|
|
105
|
+
config.adapter :typhoeus
|
|
106
|
+
config.proxy = proxy_options.compact if proxy_options[:uri]
|
|
37
107
|
end
|
|
38
|
-
|
|
108
|
+
|
|
39
109
|
con
|
|
40
110
|
end
|
|
41
111
|
|
|
42
112
|
def self.create_instance()
|
|
43
|
-
|
|
44
|
-
con = Faraday.new
|
|
113
|
+
|
|
114
|
+
con = Faraday.new do |config|
|
|
115
|
+
# 使用自定义重试中间件
|
|
116
|
+
config.use SimpleRetryMiddleware, max: 3, interval: 0.5, backoff_factor: 2
|
|
117
|
+
# 使用 Typhoeus 适配器
|
|
118
|
+
config.adapter :typhoeus
|
|
119
|
+
end
|
|
120
|
+
|
|
45
121
|
con
|
|
46
122
|
end
|
|
47
123
|
|
|
@@ -33,44 +33,62 @@ module Pindo
|
|
|
33
33
|
self.description = <<-DESC
|
|
34
34
|
编译Android工程生成APK/AAB并支持上传到JPS测试平台。
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
参数优先级说明(从低到高):
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
1. 无参数:
|
|
39
|
+
- Git 提交 → 编译 APK → 打 Git Tag
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
2. --upload:
|
|
42
|
+
- 在基础流程上增加:上传 APK → 发送消息给自己
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
3. --media:
|
|
45
|
+
- 自动启用 --upload
|
|
46
|
+
- 在 --upload 基础上增加:上传媒体附件(JPSMedia/ 目录)
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
4. --bind:
|
|
49
|
+
- 自动启用 --media 和 --upload
|
|
50
|
+
- 在 --media 基础上增加:绑定 Git commit 到已上传的包
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
5. --send:
|
|
53
|
+
- 自动启用 --bind、--media 和 --upload
|
|
54
|
+
- 在 --bind 基础上增加:发送工作流消息到测试群
|
|
55
|
+
|
|
56
|
+
支持功能:
|
|
47
57
|
|
|
58
|
+
* 自动修改工程配置(Application ID、App Name、URL Schemes)
|
|
59
|
+
* 编译生成 APK 或 AAB 文件
|
|
60
|
+
* 上传到 JPS 测试平台
|
|
61
|
+
* 上传媒体附件(图片、视频)
|
|
62
|
+
* 绑定 Git commit 到已上传的包
|
|
63
|
+
* 发送测试通知(自己/测试群)
|
|
64
|
+
* 支持 Unity 和原生 Android 工程
|
|
48
65
|
* 支持并发任务执行(使用 --multi 参数)
|
|
49
66
|
|
|
50
67
|
使用示例:
|
|
51
68
|
|
|
52
|
-
$ pindo
|
|
69
|
+
$ pindo and autobuild --bundle_name=com.example.app # 指定 Bundle Name
|
|
53
70
|
|
|
54
|
-
$ pindo
|
|
71
|
+
$ pindo and autobuild --proj="My App" # 指定项目名称
|
|
55
72
|
|
|
56
|
-
$ pindo
|
|
73
|
+
$ pindo and autobuild # 编译、打tag
|
|
57
74
|
|
|
58
|
-
$ pindo
|
|
75
|
+
$ pindo and autobuild --release # 编译 Release 包
|
|
59
76
|
|
|
60
|
-
$ pindo
|
|
77
|
+
$ pindo and autobuild --upload # 编译、打tag、上传、发上传消息
|
|
61
78
|
|
|
62
|
-
$ pindo
|
|
79
|
+
$ pindo and autobuild --media # 编译、打tag、上传、发上传消息、上传媒体附件
|
|
63
80
|
|
|
64
|
-
$ pindo
|
|
81
|
+
$ pindo and autobuild --bind # 编译、打tag、上传、发上传消息、上传媒体附件 + 绑定包到工作流
|
|
65
82
|
|
|
66
|
-
$ pindo
|
|
83
|
+
$ pindo and autobuild --send # 编译、打tag、上传、发上传消息、上传媒体附件、绑定包到工作流 + 发送群消息
|
|
67
84
|
|
|
68
|
-
$ pindo
|
|
85
|
+
$ pindo and autobuild --multi # 使用并发模式执行
|
|
69
86
|
DESC
|
|
70
87
|
|
|
71
88
|
# 定义此命令使用的参数项
|
|
72
89
|
def self.option_items
|
|
73
90
|
@option_items ||= Pindo::Options::OptionGroup.merge(
|
|
91
|
+
Pindo::Options::BuildOptions.select(:bundle_name), # 添加 bundle_name 参数
|
|
74
92
|
Pindo::Options::JPSOptions.select(:proj, :upload, :send, :media),
|
|
75
93
|
Pindo::Options::UnityOptions.select(:skiplib, :skipyoo),
|
|
76
94
|
Pindo::Options::UnityOptions.select_with_defaults(skipconfig: true),
|
|
@@ -81,8 +99,7 @@ module Pindo
|
|
|
81
99
|
|
|
82
100
|
def self.options
|
|
83
101
|
[
|
|
84
|
-
['--release', '使用Release模式构建']
|
|
85
|
-
['--bundle_name=NAME', '指定Android Package Name(如com.example.app,会拉取对应配置)']
|
|
102
|
+
['--release', '使用Release模式构建']
|
|
86
103
|
].concat(option_items.map(&:to_claide_option)).concat(super)
|
|
87
104
|
end
|
|
88
105
|
|
|
@@ -90,14 +107,23 @@ module Pindo
|
|
|
90
107
|
@options = initialize_options(argv)
|
|
91
108
|
|
|
92
109
|
@args_release_flag = argv.flag?('release', false)
|
|
93
|
-
@args_upload_flag = @options[:upload] || false
|
|
94
|
-
@args_send_flag = @options[:send] || false
|
|
95
110
|
@args_proj_name = @options[:proj]
|
|
96
|
-
@args_bundle_name =
|
|
111
|
+
@args_bundle_name = @options[:bundle_name] # 从 @options 获取,确保能被缓存
|
|
112
|
+
|
|
113
|
+
# send、media 或 bind 都依赖 upload:如果指定了任一参数,自动启用 upload
|
|
114
|
+
@args_upload_flag = @options[:send] || @options[:bind] || @options[:media] || @options[:upload]
|
|
115
|
+
|
|
116
|
+
# media 任务是独立的,不依赖任何其他任务,但是为输入命令参数更加简单,如果有--bind和--send, 则默认认为一定会有--media参数
|
|
117
|
+
@args_media_flag = @options[:send] || @options[:bind] || @options[:media] || false
|
|
118
|
+
|
|
119
|
+
# send 都依赖 bind:如果指定了任一参数,自动启用 bind
|
|
120
|
+
@args_bind_flag = @options[:send] || @options[:bind] || false
|
|
121
|
+
|
|
122
|
+
@args_send_flag = @options[:send]
|
|
123
|
+
|
|
124
|
+
# Unity 参数
|
|
97
125
|
@args_skip_lib = @options[:skiplib] || false
|
|
98
126
|
@args_skip_yoo = @options[:skipyoo] || false
|
|
99
|
-
# media 依赖 upload:如果指定了 media,自动启用 upload
|
|
100
|
-
@args_media_flag = @options[:media] || false
|
|
101
127
|
|
|
102
128
|
# Task 参数
|
|
103
129
|
@args_multi_flag = @options[:multi] || false
|
|
@@ -108,10 +134,6 @@ module Pindo
|
|
|
108
134
|
@args_tag_type = Pindo::Options::GitOptions.parse_create_tag_type(@options[:tag_type] || 'new')
|
|
109
135
|
@args_tag_pre = @options[:tag_pre] || 'v'
|
|
110
136
|
|
|
111
|
-
if @args_send_flag || @args_media_flag
|
|
112
|
-
@args_upload_flag = true
|
|
113
|
-
end
|
|
114
|
-
|
|
115
137
|
super
|
|
116
138
|
@additional_args = argv.remainder!
|
|
117
139
|
end
|
|
@@ -150,6 +172,12 @@ module Pindo
|
|
|
150
172
|
# 获取 Bundle Name
|
|
151
173
|
bundle_name = @args_bundle_name || get_selected_dev_bundle_name()
|
|
152
174
|
|
|
175
|
+
# 重要:如果 bundle_name 是通过交互式选择获取的,同步回 @options
|
|
176
|
+
if bundle_name && (@args_bundle_name.nil? || @args_bundle_name.empty?)
|
|
177
|
+
@args_bundle_name = bundle_name
|
|
178
|
+
@options[:bundle_name] = bundle_name # 确保能被缓存系统保存
|
|
179
|
+
end
|
|
180
|
+
|
|
153
181
|
# 获取 JPS 配置
|
|
154
182
|
app_info_obj, workflow_info = PgyerHelper.share_instace.prepare_upload(
|
|
155
183
|
working_directory: pindo_project_dir,
|
|
@@ -256,8 +284,6 @@ module Pindo
|
|
|
256
284
|
project_path: android_project_path,
|
|
257
285
|
bundle_name: config[:bundle_name],
|
|
258
286
|
proj_name: @args_proj_name,
|
|
259
|
-
upload: @args_upload_flag,
|
|
260
|
-
send: @args_send_flag,
|
|
261
287
|
app_info_obj: config[:app_info_obj],
|
|
262
288
|
workflow_info: config[:workflow_info],
|
|
263
289
|
# Git 版本参数
|
|
@@ -283,6 +309,7 @@ module Pindo
|
|
|
283
309
|
tasks << git_tag_task
|
|
284
310
|
|
|
285
311
|
# 5. 上传和消息发送任务(如果需要)
|
|
312
|
+
upload_task = nil # 声明变量以便后续绑定任务使用
|
|
286
313
|
if @args_upload_flag
|
|
287
314
|
# 5.1 创建上传任务
|
|
288
315
|
upload_task = Pindo::TaskSystem::JPSUploadTask.new(
|
|
@@ -296,15 +323,15 @@ module Pindo
|
|
|
296
323
|
upload_task.dependencies << build_task.id
|
|
297
324
|
tasks << upload_task
|
|
298
325
|
|
|
299
|
-
# 5.2
|
|
326
|
+
# 5.2 创建消息发送任务(只依赖上传任务,固定发送给自己)
|
|
300
327
|
# app_version_info 将从 upload_task 的数据参数中获取
|
|
301
328
|
message_task = Pindo::TaskSystem::JPSMessageTask.new(
|
|
302
329
|
nil, # app_version_info 为 nil,从依赖任务获取
|
|
303
330
|
app_info_obj: config[:app_info_obj],
|
|
304
331
|
project_name: @args_proj_name,
|
|
305
|
-
send_message_type:
|
|
306
|
-
dependencies: [upload_task.id] # 从 upload_task 获取数据
|
|
332
|
+
send_message_type: 'self' # 固定发送给自己
|
|
307
333
|
)
|
|
334
|
+
message_task.dependencies << upload_task.id
|
|
308
335
|
tasks << message_task
|
|
309
336
|
end
|
|
310
337
|
|
|
@@ -325,11 +352,52 @@ module Pindo
|
|
|
325
352
|
workflow_info: git_workflow_info,
|
|
326
353
|
project_name: @args_proj_name
|
|
327
354
|
)
|
|
328
|
-
#
|
|
355
|
+
# 依赖 Git 提交任务
|
|
329
356
|
media_upload_task.dependencies << git_commit_task.id
|
|
330
357
|
tasks << media_upload_task
|
|
331
358
|
end
|
|
332
359
|
|
|
360
|
+
# 7. 创建 Git Commit 绑定任务(如果需要,依赖上传任务)
|
|
361
|
+
bind_package_task = nil # 声明变量以便后续工作流消息任务使用
|
|
362
|
+
if @args_bind_flag
|
|
363
|
+
bind_package_task = Pindo::TaskSystem::JPSBindPackageTask.new(
|
|
364
|
+
nil, # app_version_list 为 nil,从依赖任务获取
|
|
365
|
+
project_dir: config[:project_path],
|
|
366
|
+
app_info_obj: config[:app_info_obj],
|
|
367
|
+
workflow_info: config[:workflow_info],
|
|
368
|
+
project_name: @args_proj_name
|
|
369
|
+
)
|
|
370
|
+
# 依赖上传任务和 Git 提交任务
|
|
371
|
+
bind_package_task.dependencies << upload_task.id
|
|
372
|
+
bind_package_task.dependencies << git_commit_task.id
|
|
373
|
+
tasks << bind_package_task
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
# 8. 创建工作流消息任务(如果需要,发送到测试群)
|
|
377
|
+
if @args_send_flag
|
|
378
|
+
# 获取 Git 工作流信息
|
|
379
|
+
git_app_info_obj, git_workflow_info = PgyerHelper.share_instace.prepare_upload(
|
|
380
|
+
working_directory: config[:project_path],
|
|
381
|
+
proj_name: @args_proj_name,
|
|
382
|
+
package_type: "",
|
|
383
|
+
manage_type: "git"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
workflow_message_task = Pindo::TaskSystem::JPSWorkFlowMessageTask.new(
|
|
387
|
+
project_id: git_app_info_obj["id"],
|
|
388
|
+
workflow_id: git_workflow_info["id"],
|
|
389
|
+
branch: 'master',
|
|
390
|
+
single: true,
|
|
391
|
+
app_info_obj: git_app_info_obj,
|
|
392
|
+
workflow_info: git_workflow_info
|
|
393
|
+
)
|
|
394
|
+
# 依赖 Git Commit、Git Tag 和 Bind Package 任务
|
|
395
|
+
workflow_message_task.dependencies << git_commit_task.id
|
|
396
|
+
workflow_message_task.dependencies << git_tag_task.id
|
|
397
|
+
workflow_message_task.dependencies << bind_package_task.id
|
|
398
|
+
tasks << workflow_message_task
|
|
399
|
+
end
|
|
400
|
+
|
|
333
401
|
tasks
|
|
334
402
|
else
|
|
335
403
|
raise Informative, "当前目录不是工程目录,不能编译"
|