pindo 5.20.0 → 5.20.1
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 +52 -7
- data/lib/pindo/command/jps/apptest.rb +6 -3
- data/lib/pindo/command/jps/bind.rb +6 -2
- data/lib/pindo/command/jps/config.rb +354 -0
- data/lib/pindo/command/jps/download.rb +3 -2
- data/lib/pindo/command/jps/media.rb +6 -2
- data/lib/pindo/command/jps/upload.rb +6 -2
- data/lib/pindo/command/jps.rb +1 -0
- data/lib/pindo/module/pgyer/pgyerhelper.rb +259 -100
- data/lib/pindo/module/source_files_guard.rb +83 -0
- data/lib/pindo/module/task/model/build/ios_build_dev_task.rb +3 -3
- data/lib/pindo/module/task/model/git/git_commit_task.rb +12 -2
- data/lib/pindo/module/task/model/git/git_tag_task.rb +66 -10
- data/lib/pindo/options/groups/jps_options.rb +43 -0
- data/lib/pindo/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d9130519bcd67f9216d72127ff62259c9ee2af59836b59ed04b7e0b3f2c5e187
|
|
4
|
+
data.tar.gz: 35c3134a7b87562fbdad8481d3cb27c0682918c88c58b4e3cdef6072a1a8a24f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9b16bb204b8047c7690baa0c25aa0704ab1d6e119b12b4ec60c41fd556111ff4725d6b76ad703f9f3953cdd5c114397086dea5432d858330fdfdbbe4781f2bd
|
|
7
|
+
data.tar.gz: 2ab33df32230c956a7e72a857471edcec4531d74c1ced69dadb0ce1259952e76d828f6f3428622c503d0a2e743b0c9d64bc328bf68a45c46b6c63dfa6b6bfab5
|
|
@@ -123,15 +123,60 @@ module Pindo
|
|
|
123
123
|
|
|
124
124
|
def local_branch_exists?(local_repo_dir: nil, branch: nil)
|
|
125
125
|
# 命令改带 -C,去掉 Dir.chdir(并发模式下 chdir 会污染全局 cwd)
|
|
126
|
-
|
|
126
|
+
return false unless local_repo_dir && File.exist?(local_repo_dir)
|
|
127
|
+
return false if branch.nil? || branch.to_s.strip.empty?
|
|
128
|
+
|
|
129
|
+
# 注意:capture_command(:capture => :out) 返回 [stdout, status] 数组,
|
|
130
|
+
# 必须判断 stdout 内容而非整个数组(数组恒非空会误判任何分支“存在”)。
|
|
131
|
+
# 用 show-ref --verify 精确校验本地分支 refs/heads/<branch>。
|
|
132
|
+
res_data = Executable.capture_command('git', %W(-C #{local_repo_dir} show-ref --verify refs/heads/#{branch}), :capture => :out)
|
|
133
|
+
stdout = res_data.is_a?(Array) ? res_data.first.to_s : res_data.to_s
|
|
134
|
+
!stdout.strip.empty?
|
|
135
|
+
end
|
|
127
136
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
137
|
+
# 列出远程分支短名(去掉 origin/ 前缀与 HEAD 指针)。使用本地 remote-tracking 引用,不触发网络。
|
|
138
|
+
def remote_branch_names(local_repo_dir: nil)
|
|
139
|
+
return [] unless local_repo_dir && File.exist?(local_repo_dir)
|
|
140
|
+
out = git!(%W(-C #{local_repo_dir} for-each-ref --format=%(refname:short) refs/remotes/origin))
|
|
141
|
+
return [] if out.nil? || out.strip.empty?
|
|
142
|
+
# 仅取 "origin/<branch>";origin/HEAD 的短名会缩写为裸 "origin",需排除
|
|
143
|
+
out.lines.map(&:strip)
|
|
144
|
+
.select { |name| name.start_with?('origin/') }
|
|
145
|
+
.map { |name| name.sub(%r{\Aorigin/}, '') }
|
|
146
|
+
.reject { |name| name.empty? || name == 'HEAD' }
|
|
147
|
+
.uniq
|
|
148
|
+
rescue => e
|
|
149
|
+
[]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# 解析发布分支(当用户未显式指定时给出合理默认):
|
|
153
|
+
# 1) preferred(用户 --release_branch 或默认值)在远程存在 → 用它(master 仓库、显式指定均走此)
|
|
154
|
+
# 2) 否则远程有 master → master
|
|
155
|
+
# 3) 否则远程有 main → main
|
|
156
|
+
# 4) 否则只有唯一远程分支 → 用它
|
|
157
|
+
# 5) 兜底:当前分支(避免往不存在的分支同步而报错)
|
|
158
|
+
# @param local_repo_dir [String] 仓库目录
|
|
159
|
+
# @param preferred [String, nil] 期望的发布分支
|
|
160
|
+
# @return [String] 解析后的发布分支名
|
|
161
|
+
def resolve_release_branch(local_repo_dir: nil, preferred: nil)
|
|
162
|
+
current = (git!(%W(-C #{local_repo_dir} rev-parse --abbrev-ref HEAD)).strip rescue nil)
|
|
163
|
+
remotes = remote_branch_names(local_repo_dir: local_repo_dir)
|
|
164
|
+
pref = preferred.to_s.strip
|
|
165
|
+
|
|
166
|
+
# 无法获取远程分支(网络异常/未 fetch)→ 退回当前分支,跳过跨分支同步,避免误操作
|
|
167
|
+
if remotes.empty?
|
|
168
|
+
return current unless current.nil? || current.empty?
|
|
169
|
+
return pref.empty? ? 'master' : pref
|
|
133
170
|
end
|
|
134
|
-
|
|
171
|
+
|
|
172
|
+
return pref if !pref.empty? && remotes.include?(pref)
|
|
173
|
+
return 'master' if remotes.include?('master')
|
|
174
|
+
return 'main' if remotes.include?('main')
|
|
175
|
+
return remotes.first if remotes.size == 1
|
|
176
|
+
# 多远程分支且无 master/main/preferred:退回当前分支(coding==release,跳过跨分支同步,
|
|
177
|
+
# 避免退回到可能不存在的 preferred 而在 checkout 时报错)
|
|
178
|
+
return current if current && !current.strip.empty? && current != 'HEAD'
|
|
179
|
+
pref.empty? ? 'master' : pref
|
|
135
180
|
end
|
|
136
181
|
|
|
137
182
|
def remote_branch_exists?(local_repo_dir: nil, branch: nil)
|
|
@@ -37,7 +37,7 @@ module Pindo
|
|
|
37
37
|
# 定义此命令使用的参数项
|
|
38
38
|
def self.option_items
|
|
39
39
|
@option_items ||= Pindo::Options::OptionGroup.merge(
|
|
40
|
-
Pindo::Options::JPSOptions.select(:conf, :send, :list, :group)
|
|
40
|
+
Pindo::Options::JPSOptions.select(:conf, :send, :list, :group, :proj)
|
|
41
41
|
)
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -54,6 +54,7 @@ module Pindo
|
|
|
54
54
|
@args_list_flag = @options[:list] || false
|
|
55
55
|
@args_send_flag = @options[:send] || false
|
|
56
56
|
@args_group_flag = @options[:group] || false
|
|
57
|
+
@args_proj = @options[:proj]
|
|
57
58
|
|
|
58
59
|
super(argv)
|
|
59
60
|
end
|
|
@@ -72,7 +73,8 @@ module Pindo
|
|
|
72
73
|
app_info_obj, workflow_info = pgyer_helper.prepare_upload(
|
|
73
74
|
working_directory: project_path,
|
|
74
75
|
conf: @args_conf,
|
|
75
|
-
package_type: 'ipa' # 获取 IPA 工作流信息
|
|
76
|
+
package_type: 'ipa', # 获取 IPA 工作流信息
|
|
77
|
+
proj_name: @args_proj
|
|
76
78
|
)
|
|
77
79
|
|
|
78
80
|
if app_info_obj.nil?
|
|
@@ -115,7 +117,8 @@ module Pindo
|
|
|
115
117
|
working_directory: project_path,
|
|
116
118
|
conf: @args_conf,
|
|
117
119
|
package_type: nil,
|
|
118
|
-
manage_type: "git"
|
|
120
|
+
manage_type: "git",
|
|
121
|
+
proj_name: @args_proj
|
|
119
122
|
)
|
|
120
123
|
|
|
121
124
|
# 获取 git_commit_id
|
|
@@ -37,7 +37,7 @@ module Pindo
|
|
|
37
37
|
# 定义此命令使用的参数项
|
|
38
38
|
def self.option_items
|
|
39
39
|
@option_items ||= Pindo::Options::OptionGroup.merge(
|
|
40
|
-
Pindo::Options::JPSOptions.select(:conf),
|
|
40
|
+
Pindo::Options::JPSOptions.select(:conf, :proj, :workflow_name),
|
|
41
41
|
Pindo::Options::TaskOptions.select(:select),
|
|
42
42
|
Pindo::Options::GitOptions.all
|
|
43
43
|
)
|
|
@@ -53,6 +53,8 @@ module Pindo
|
|
|
53
53
|
|
|
54
54
|
# JPS 参数
|
|
55
55
|
@args_conf = @options[:conf]
|
|
56
|
+
@args_proj = @options[:proj]
|
|
57
|
+
@args_workflow_name = @options[:workflow_name]
|
|
56
58
|
|
|
57
59
|
# Task 参数
|
|
58
60
|
@args_select_flag = @options[:select] || false
|
|
@@ -95,7 +97,9 @@ module Pindo
|
|
|
95
97
|
working_directory: project_path,
|
|
96
98
|
conf: @args_conf,
|
|
97
99
|
package_type: nil,
|
|
98
|
-
manage_type: "git"
|
|
100
|
+
manage_type: "git",
|
|
101
|
+
proj_name: @args_proj,
|
|
102
|
+
workflow_name: @args_workflow_name
|
|
99
103
|
)
|
|
100
104
|
|
|
101
105
|
if app_info_obj.nil?
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'pindo/module/pgyer/pgyerhelper'
|
|
4
|
+
require 'pindo/module/build/build_helper'
|
|
5
|
+
require 'pindo/options/options'
|
|
6
|
+
require 'pindo/options/groups/jps_options'
|
|
7
|
+
|
|
8
|
+
module Pindo
|
|
9
|
+
class Command
|
|
10
|
+
class Jps < Command
|
|
11
|
+
class Config < Jps
|
|
12
|
+
|
|
13
|
+
self.summary = '配置当前工程与 JPS 项目及工作流的绑定'
|
|
14
|
+
|
|
15
|
+
self.description = <<-DESC
|
|
16
|
+
将当前工程绑定到 JPS 项目及其一个或多个工作流,并写入 JPSBuildConfig.json。
|
|
17
|
+
|
|
18
|
+
只做配置绑定,不编译、不上传,产出与 pindo ios/and autobuild 一致的配置文件。
|
|
19
|
+
|
|
20
|
+
支持功能:
|
|
21
|
+
|
|
22
|
+
* 选一次 JPS 项目,一次配置多个工作流类型
|
|
23
|
+
* 交互多选菜单,或用 --type 非交互指定类型
|
|
24
|
+
* --proj 直接指定项目名,跳过项目选择菜单(非交互场景)
|
|
25
|
+
* --workflow_name 按名称指定工作流,用于同类型多工作流消歧(非交互场景)
|
|
26
|
+
* 支持类型: ipa、apk、zip(WebGL)、mac(macOS)、exe(Windows)、git
|
|
27
|
+
* --clean 清除已绑定的工作流或整个配置文件
|
|
28
|
+
|
|
29
|
+
使用示例:
|
|
30
|
+
|
|
31
|
+
$ pindo jps config # 交互选择项目和工作流类型
|
|
32
|
+
|
|
33
|
+
$ pindo jps config --type=ipa,apk,git # 非交互配置指定类型(项目仍需交互选)
|
|
34
|
+
|
|
35
|
+
$ pindo jps config --proj=MyApp --type=ipa,git # 全程非交互(agent/CI 适用)
|
|
36
|
+
|
|
37
|
+
$ pindo jps config --clean # 交互清除已绑定的工作流
|
|
38
|
+
|
|
39
|
+
$ pindo jps config --clean --type=ipa # 清除指定类型的绑定
|
|
40
|
+
|
|
41
|
+
DESC
|
|
42
|
+
|
|
43
|
+
self.arguments = [
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# 工作流类型定义表(key、显示名、package_type、manage_type、配置文件中的 workflow_key)
|
|
47
|
+
WORKFLOW_TYPES = [
|
|
48
|
+
{ key: 'ipa', name: 'iOS IPA', package_type: 'ipa', manage_type: '', workflow_key: 'ipa_workflow' },
|
|
49
|
+
{ key: 'apk', name: 'Android APK', package_type: 'apk', manage_type: '', workflow_key: 'apk_workflow' },
|
|
50
|
+
{ key: 'zip', name: 'WebGL', package_type: 'zip', manage_type: '', workflow_key: 'webgl_workflow' },
|
|
51
|
+
{ key: 'mac', name: 'macOS', package_type: 'mac', manage_type: '', workflow_key: 'macos_workflow' },
|
|
52
|
+
{ key: 'exe', name: 'Windows', package_type: 'exe', manage_type: '', workflow_key: 'win_workflow' },
|
|
53
|
+
{ key: 'git', name: 'Git 提交', package_type: nil, manage_type: 'git', workflow_key: 'git_workflow' }
|
|
54
|
+
].freeze
|
|
55
|
+
|
|
56
|
+
DIVIDER = ('━' * 60).freeze
|
|
57
|
+
|
|
58
|
+
def self.option_items
|
|
59
|
+
@option_items ||= Pindo::Options::JPSOptions.select(:conf, :type, :clean, :proj, :workflow_name)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.options
|
|
63
|
+
option_items.map(&:to_claide_option).concat(super)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def initialize(argv)
|
|
67
|
+
@options = initialize_options(argv)
|
|
68
|
+
|
|
69
|
+
@args_conf = @options[:conf]
|
|
70
|
+
@args_type = parse_type_option(@options[:type])
|
|
71
|
+
@args_clean = @options[:clean] || false
|
|
72
|
+
@args_proj = @options[:proj]
|
|
73
|
+
@args_workflow_name = @options[:workflow_name]
|
|
74
|
+
|
|
75
|
+
super(argv)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def validate!
|
|
79
|
+
super
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def run
|
|
83
|
+
if @args_clean
|
|
84
|
+
run_clean
|
|
85
|
+
else
|
|
86
|
+
run_config
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
# ===== 配置写入流程 =====
|
|
93
|
+
|
|
94
|
+
def run_config
|
|
95
|
+
project_path = Dir.pwd
|
|
96
|
+
|
|
97
|
+
selected_types = resolve_selected_types
|
|
98
|
+
if selected_types.empty?
|
|
99
|
+
puts "未选择任何工作流类型,已取消操作"
|
|
100
|
+
return
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
pgyer_helper = PgyerHelper.share_instace
|
|
104
|
+
unless pgyer_helper.login
|
|
105
|
+
raise Informative, "JPS 未登录或登录已失效,请执行 pindo jps login 重新登录"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
app_info_obj = resolve_project(pgyer_helper, project_path)
|
|
109
|
+
if app_info_obj.nil?
|
|
110
|
+
raise Informative, "未找到 JPS 项目,请检查项目名称或配置文件"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Phase 1: 先选定所有类型的工作流(任一歧义/缺失即报错,此时尚未写任何文件)
|
|
114
|
+
selections = selected_types.map do |type|
|
|
115
|
+
puts "\n选择工作流: #{type[:name]}"
|
|
116
|
+
workflow_info = pgyer_helper.select_workflow_for_project(
|
|
117
|
+
project_id: app_info_obj["id"],
|
|
118
|
+
package_type: type[:package_type],
|
|
119
|
+
working_directory: project_path,
|
|
120
|
+
manage_type: type[:manage_type],
|
|
121
|
+
workflow_name: @args_workflow_name
|
|
122
|
+
)
|
|
123
|
+
{ type: type, workflow_info: workflow_info }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Phase 2: 全部选定后一次性原子写盘(单次 rename),避免中途失败留下半成品配置
|
|
127
|
+
pgyer_helper.save_jps_workflows(
|
|
128
|
+
working_directory: project_path,
|
|
129
|
+
app_info_obj: app_info_obj,
|
|
130
|
+
conf: @args_conf,
|
|
131
|
+
entries: selections.map do |sel|
|
|
132
|
+
{
|
|
133
|
+
package_type: sel[:type][:package_type],
|
|
134
|
+
manage_type: sel[:type][:manage_type],
|
|
135
|
+
workflow_info: sel[:workflow_info]
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
print_config_summary(project_path)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# 解析 JPS 项目:--proj 指定则直接查找(非交互),否则回退交互选择
|
|
144
|
+
# @return [Hash, nil] JPS 项目信息对象
|
|
145
|
+
def resolve_project(pgyer_helper, project_path)
|
|
146
|
+
if @args_proj && !@args_proj.strip.empty?
|
|
147
|
+
app_info_obj = pgyer_helper.find_app_info_with_obj_list(proj_name: @args_proj, strict: true)
|
|
148
|
+
if app_info_obj.nil?
|
|
149
|
+
raise Informative, "JPS 上未找到项目: #{@args_proj},请检查项目名称"
|
|
150
|
+
end
|
|
151
|
+
return app_info_obj
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# 未指定 --proj:package_type 传 nil,仅完成交互项目选择,返回单个 app_info_obj
|
|
155
|
+
pgyer_helper.prepare_upload(
|
|
156
|
+
working_directory: project_path,
|
|
157
|
+
conf: @args_conf
|
|
158
|
+
)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# 解析要配置的工作流类型:--type 优先,否则交互多选
|
|
162
|
+
# @return [Array<Hash>] WORKFLOW_TYPES 条目数组
|
|
163
|
+
def resolve_selected_types
|
|
164
|
+
if @args_type
|
|
165
|
+
return @args_type.map { |key| find_type!(key) }.uniq
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
select_types_interactive
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def select_types_interactive
|
|
172
|
+
puts "\n请选择要配置的工作流类型(可多选):"
|
|
173
|
+
puts DIVIDER
|
|
174
|
+
WORKFLOW_TYPES.each_with_index do |type, index|
|
|
175
|
+
puts " #{index + 1}. #{type[:name]}"
|
|
176
|
+
end
|
|
177
|
+
puts " 0. 取消操作"
|
|
178
|
+
puts DIVIDER
|
|
179
|
+
|
|
180
|
+
print "\n请输入序号(多个用逗号分隔,如 1,3): "
|
|
181
|
+
input = $stdin.gets.to_s.strip
|
|
182
|
+
return [] if input == '0' || input.empty?
|
|
183
|
+
|
|
184
|
+
selected = parse_menu_input(input, WORKFLOW_TYPES)
|
|
185
|
+
puts "无效输入,未选择任何类型" if selected.empty?
|
|
186
|
+
selected
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# ===== 清除流程 =====
|
|
190
|
+
|
|
191
|
+
def run_clean
|
|
192
|
+
config_file = resolve_config_path(Dir.pwd)
|
|
193
|
+
|
|
194
|
+
unless File.exist?(config_file)
|
|
195
|
+
puts "当前工程未找到 JPSBuildConfig.json,无需清除"
|
|
196
|
+
return
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
begin
|
|
200
|
+
config = JSON.parse(File.read(config_file))
|
|
201
|
+
rescue => e
|
|
202
|
+
raise Informative, "读取配置文件失败: #{e.message}"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
present_types = WORKFLOW_TYPES.select { |type| config.key?(type[:workflow_key]) }
|
|
206
|
+
if present_types.empty?
|
|
207
|
+
puts "配置文件中没有已绑定的工作流,无需清除"
|
|
208
|
+
return
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
remove_whole, target_types = resolve_clean_targets(present_types)
|
|
212
|
+
if !remove_whole && target_types.empty?
|
|
213
|
+
puts "未选择任何内容,已取消清除"
|
|
214
|
+
return
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
desc = remove_whole ? "整个 JPSBuildConfig.json 文件" : target_types.map { |type| type[:name] }.join('、')
|
|
218
|
+
unless confirm_clean(desc)
|
|
219
|
+
puts "已取消清除"
|
|
220
|
+
return
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
if remove_whole
|
|
224
|
+
File.delete(config_file)
|
|
225
|
+
puts "已删除 #{config_file}"
|
|
226
|
+
return
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
target_types.each { |type| config.delete(type[:workflow_key]) }
|
|
230
|
+
|
|
231
|
+
if WORKFLOW_TYPES.any? { |type| config.key?(type[:workflow_key]) }
|
|
232
|
+
atomic_write_file(config_file, JSON.pretty_generate(config) + "\n")
|
|
233
|
+
puts "已清除: #{target_types.map { |type| type[:name] }.join('、')}"
|
|
234
|
+
else
|
|
235
|
+
File.delete(config_file)
|
|
236
|
+
puts "已清除全部工作流,删除 #{config_file}"
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# 解析清除目标
|
|
241
|
+
# @return [Array(Boolean, Array<Hash>)] [是否清除整份文件, 要清除的类型数组]
|
|
242
|
+
def resolve_clean_targets(present_types)
|
|
243
|
+
if @args_type
|
|
244
|
+
targets = @args_type.map do |key|
|
|
245
|
+
type = present_types.find { |t| t[:key] == key }
|
|
246
|
+
if type.nil?
|
|
247
|
+
raise Informative, "配置文件中未绑定该类型: #{key}(已绑定: #{present_types.map { |t| t[:key] }.join(', ')})"
|
|
248
|
+
end
|
|
249
|
+
type
|
|
250
|
+
end
|
|
251
|
+
return [false, targets.uniq]
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
puts "\n请选择要清除的工作流(可多选):"
|
|
255
|
+
puts DIVIDER
|
|
256
|
+
present_types.each_with_index do |type, index|
|
|
257
|
+
puts " #{index + 1}. #{type[:name]}"
|
|
258
|
+
end
|
|
259
|
+
all_index = present_types.size + 1
|
|
260
|
+
puts " #{all_index}. 清除整个配置文件"
|
|
261
|
+
puts " 0. 取消操作"
|
|
262
|
+
puts DIVIDER
|
|
263
|
+
|
|
264
|
+
print "\n请输入序号(多个用逗号分隔): "
|
|
265
|
+
input = $stdin.gets.to_s.strip
|
|
266
|
+
return [false, []] if input == '0' || input.empty?
|
|
267
|
+
|
|
268
|
+
nums = input.split(',').map { |num_str| num_str.strip.to_i }
|
|
269
|
+
return [true, []] if nums.include?(all_index)
|
|
270
|
+
|
|
271
|
+
targets = []
|
|
272
|
+
nums.each { |num| targets << present_types[num - 1] if num > 0 && num <= present_types.size }
|
|
273
|
+
[false, targets.uniq]
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def confirm_clean(desc)
|
|
277
|
+
return true if ENV['PINDO_AUTO_CONFIRM'] && !ENV['PINDO_AUTO_CONFIRM'].empty?
|
|
278
|
+
|
|
279
|
+
require 'highline/import'
|
|
280
|
+
puts "\n即将清除: #{desc}"
|
|
281
|
+
agree("确认清除吗?(yes/no) ")
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# ===== 通用辅助 =====
|
|
285
|
+
|
|
286
|
+
# 解析 --type 参数为类型 key 数组,未指定返回 nil
|
|
287
|
+
def parse_type_option(raw_type)
|
|
288
|
+
return nil if raw_type.nil? || raw_type.strip.empty?
|
|
289
|
+
keys = raw_type.split(',').map { |part| part.strip.downcase }.reject(&:empty?)
|
|
290
|
+
keys.empty? ? nil : keys
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def find_type!(key)
|
|
294
|
+
type = WORKFLOW_TYPES.find { |t| t[:key] == key }
|
|
295
|
+
if type.nil?
|
|
296
|
+
raise Informative, "不支持的工作流类型: #{key}(可选: #{WORKFLOW_TYPES.map { |t| t[:key] }.join(', ')})"
|
|
297
|
+
end
|
|
298
|
+
type
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# 解析菜单多选输入为类型数组
|
|
302
|
+
def parse_menu_input(input, type_list)
|
|
303
|
+
selected = []
|
|
304
|
+
input.split(',').each do |num_str|
|
|
305
|
+
num = num_str.strip.to_i
|
|
306
|
+
selected << type_list[num - 1] if num > 0 && num <= type_list.size
|
|
307
|
+
end
|
|
308
|
+
selected.uniq
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# 原子写文件:同目录临时文件 + rename,避免半写并以普通文件替换符号链接(不写穿目标)
|
|
312
|
+
def atomic_write_file(path, content)
|
|
313
|
+
dir = File.dirname(path)
|
|
314
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
|
315
|
+
tmp = File.join(dir, ".#{File.basename(path)}.#{Process.pid}.tmp")
|
|
316
|
+
begin
|
|
317
|
+
File.write(tmp, content)
|
|
318
|
+
File.rename(tmp, path)
|
|
319
|
+
ensure
|
|
320
|
+
File.delete(tmp) if File.exist?(tmp)
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def resolve_config_path(project_path)
|
|
325
|
+
if @args_conf && !@args_conf.empty?
|
|
326
|
+
File.expand_path(@args_conf)
|
|
327
|
+
else
|
|
328
|
+
Pindo::BuildHelper.share_instance.determine_jps_config_path(project_path)
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def print_config_summary(project_path)
|
|
333
|
+
config_file = resolve_config_path(project_path)
|
|
334
|
+
return unless File.exist?(config_file)
|
|
335
|
+
|
|
336
|
+
config = JSON.parse(File.read(config_file)) rescue nil
|
|
337
|
+
return if config.nil?
|
|
338
|
+
|
|
339
|
+
puts "\n#{DIVIDER}"
|
|
340
|
+
puts "JPSBuildConfig.json 配置已更新:"
|
|
341
|
+
puts " 文件: #{config_file}"
|
|
342
|
+
puts " 项目: #{config['project_name']} (ID: #{config['project_id']})"
|
|
343
|
+
WORKFLOW_TYPES.each do |type|
|
|
344
|
+
workflow = config[type[:workflow_key]]
|
|
345
|
+
next if workflow.nil?
|
|
346
|
+
puts " #{type[:name]}: #{workflow['tab_name']} (ID: #{workflow['workflow_id']})"
|
|
347
|
+
end
|
|
348
|
+
puts DIVIDER
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
end
|
|
@@ -36,7 +36,7 @@ module Pindo
|
|
|
36
36
|
]
|
|
37
37
|
|
|
38
38
|
def self.option_items
|
|
39
|
-
@option_items ||= Pindo::Options::JPSOptions.select(:login, :list, :conf, :index)
|
|
39
|
+
@option_items ||= Pindo::Options::JPSOptions.select(:login, :list, :conf, :index, :proj)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def self.options
|
|
@@ -50,6 +50,7 @@ module Pindo
|
|
|
50
50
|
@args_list_flag = @options[:list] || false
|
|
51
51
|
@args_conf = @options[:conf]
|
|
52
52
|
@app_version_index = @options[:index]
|
|
53
|
+
@args_proj = @options[:proj]
|
|
53
54
|
|
|
54
55
|
super(argv)
|
|
55
56
|
@additional_args = argv.remainder!
|
|
@@ -63,7 +64,7 @@ module Pindo
|
|
|
63
64
|
def run
|
|
64
65
|
|
|
65
66
|
PgyerHelper.share_instace.setForeLogin(beforeLogin:@args_login_flag)
|
|
66
|
-
app_info_obj = PgyerHelper.share_instace.prepare_upload(working_directory:Dir.pwd, conf:@args_conf)
|
|
67
|
+
app_info_obj = PgyerHelper.share_instace.prepare_upload(working_directory:Dir.pwd, conf:@args_conf, proj_name:@args_proj)
|
|
67
68
|
|
|
68
69
|
if app_info_obj.nil?
|
|
69
70
|
raise Informative, "未找到 JPS 项目,请检查配置文件或重新选择"
|
|
@@ -44,7 +44,7 @@ module Pindo
|
|
|
44
44
|
# 定义此命令使用的参数项
|
|
45
45
|
def self.option_items
|
|
46
46
|
@option_items ||= Pindo::Options::OptionGroup.merge(
|
|
47
|
-
Pindo::Options::JPSOptions.select(:conf),
|
|
47
|
+
Pindo::Options::JPSOptions.select(:conf, :proj, :workflow_name),
|
|
48
48
|
Pindo::Options::TaskOptions.select(:select),
|
|
49
49
|
Pindo::Options::GitOptions.all
|
|
50
50
|
)
|
|
@@ -66,6 +66,8 @@ module Pindo
|
|
|
66
66
|
|
|
67
67
|
# JPS 参数
|
|
68
68
|
@args_conf = @options[:conf]
|
|
69
|
+
@args_proj = @options[:proj]
|
|
70
|
+
@args_workflow_name = @options[:workflow_name]
|
|
69
71
|
|
|
70
72
|
# Task 参数
|
|
71
73
|
@args_select_flag = @options[:select] || false
|
|
@@ -106,7 +108,9 @@ module Pindo
|
|
|
106
108
|
working_directory: project_path,
|
|
107
109
|
conf: @args_conf,
|
|
108
110
|
package_type: nil, # package_type 在 manage_type=git 时会被忽略
|
|
109
|
-
manage_type: "git"
|
|
111
|
+
manage_type: "git",
|
|
112
|
+
proj_name: @args_proj,
|
|
113
|
+
workflow_name: @args_workflow_name
|
|
110
114
|
)
|
|
111
115
|
|
|
112
116
|
if app_info_obj.nil?
|
|
@@ -67,7 +67,7 @@ module Pindo
|
|
|
67
67
|
def self.option_items
|
|
68
68
|
@option_items ||= Pindo::Options::OptionGroup.merge(
|
|
69
69
|
Pindo::Options::BuildOptions.select(:types),
|
|
70
|
-
Pindo::Options::JPSOptions.select(:conf, :send, :desc, :resign, :login, :file, :attach),
|
|
70
|
+
Pindo::Options::JPSOptions.select(:conf, :send, :desc, :resign, :login, :file, :attach, :proj, :workflow_name),
|
|
71
71
|
Pindo::Options::GitOptions.all
|
|
72
72
|
)
|
|
73
73
|
end
|
|
@@ -97,6 +97,8 @@ module Pindo
|
|
|
97
97
|
|
|
98
98
|
# JPS 参数
|
|
99
99
|
@args_conf = @options[:conf]
|
|
100
|
+
@args_proj = @options[:proj]
|
|
101
|
+
@args_workflow_name = @options[:workflow_name]
|
|
100
102
|
@args_send_flag = @options[:send] || false
|
|
101
103
|
@args_resign_flag = @options[:resign] || false
|
|
102
104
|
@args_upload_desc = @options[:desc]
|
|
@@ -503,7 +505,9 @@ module Pindo
|
|
|
503
505
|
app_info_obj, workflow_info = PgyerHelper.share_instace.prepare_upload(
|
|
504
506
|
working_directory: Dir.pwd,
|
|
505
507
|
conf: @args_conf,
|
|
506
|
-
package_type: package_type
|
|
508
|
+
package_type: package_type,
|
|
509
|
+
proj_name: @args_proj,
|
|
510
|
+
workflow_name: @args_workflow_name
|
|
507
511
|
)
|
|
508
512
|
|
|
509
513
|
if app_info_obj.nil?
|