pindo 5.21.5 → 5.22.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.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 683bf46a8095e20c20a6fdc339b99a6ae83337dc58431b67fb6b1d00263e42a8
|
|
4
|
+
data.tar.gz: 291caf87a1647dc8af05b26fbbfa94cd588385177869e43ec5983db3e90233f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1d0176e844e360885e6bf90ebd9024b1982ee7c519ce6d01f3fe994e085110b12107f34271d379283ca4ca27165e0cb1d2187a1daf4cfcbc2ce65b3445688786
|
|
7
|
+
data.tar.gz: 5a94ae4f340b1cc924a0e85e1c0a57272014d58c7498d248f91ab5d3d6bba399f2d3521c1d6d90dec2d5b5fdb578d4d05b1ce02b3bf55fd7ecc3eb90837a4e64
|
|
@@ -10,31 +10,31 @@ module Pindo
|
|
|
10
10
|
class Jps < Command
|
|
11
11
|
class Config < Jps
|
|
12
12
|
|
|
13
|
-
self.summary = '配置当前工程与 JPS
|
|
13
|
+
self.summary = '配置当前工程与 JPS 项目及安装包工具 / Git 工作流的绑定'
|
|
14
14
|
|
|
15
15
|
self.description = <<-DESC
|
|
16
|
-
将当前工程绑定到 JPS
|
|
16
|
+
将当前工程绑定到 JPS 项目的安装包工具(ipa/apk/zip/mac/exe)和 Git 工作流,并写入 JPSBuildConfig.json。
|
|
17
17
|
|
|
18
18
|
只做配置绑定,不编译、不上传,产出与 pindo ios/and autobuild 一致的配置文件。
|
|
19
19
|
|
|
20
20
|
支持功能:
|
|
21
21
|
|
|
22
|
-
* 选一次 JPS
|
|
22
|
+
* 选一次 JPS 项目,一次配置多个类型
|
|
23
23
|
* 交互多选菜单,或用 --type 非交互指定类型
|
|
24
24
|
* --proj 直接指定项目名,跳过项目选择菜单(非交互场景)
|
|
25
|
-
* --workflow_name
|
|
25
|
+
* --workflow_name 按名称指定 Git 工作流或安装包工具,用于同类型多个时消歧(非交互场景)
|
|
26
26
|
* 支持类型: ipa、apk、zip(WebGL)、mac(macOS)、exe(Windows)、git
|
|
27
|
-
* --clean
|
|
27
|
+
* --clean 清除已绑定的工具 / 工作流或整个配置文件
|
|
28
28
|
|
|
29
29
|
使用示例:
|
|
30
30
|
|
|
31
|
-
$ pindo jps config #
|
|
31
|
+
$ pindo jps config # 交互选择项目和绑定类型
|
|
32
32
|
|
|
33
33
|
$ pindo jps config --type=ipa,apk,git # 非交互配置指定类型(项目仍需交互选)
|
|
34
34
|
|
|
35
35
|
$ pindo jps config --proj=MyApp --type=ipa,git # 全程非交互(agent/CI 适用)
|
|
36
36
|
|
|
37
|
-
$ pindo jps config --clean #
|
|
37
|
+
$ pindo jps config --clean # 交互清除已绑定的工具 / 工作流
|
|
38
38
|
|
|
39
39
|
$ pindo jps config --clean --type=ipa # 清除指定类型的绑定
|
|
40
40
|
|
|
@@ -96,7 +96,7 @@ module Pindo
|
|
|
96
96
|
|
|
97
97
|
selected_types = resolve_selected_types
|
|
98
98
|
if selected_types.empty?
|
|
99
|
-
puts "
|
|
99
|
+
puts "未选择任何绑定类型,已取消操作"
|
|
100
100
|
return
|
|
101
101
|
end
|
|
102
102
|
|
|
@@ -110,9 +110,9 @@ module Pindo
|
|
|
110
110
|
raise Informative, "未找到 JPS 项目,请检查项目名称或配置文件"
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
-
# Phase 1:
|
|
113
|
+
# Phase 1: 先选定所有类型的工具 / 工作流(任一歧义/缺失即报错,此时尚未写任何文件)
|
|
114
114
|
selections = selected_types.map do |type|
|
|
115
|
-
puts "\n
|
|
115
|
+
puts "\n选择#{binding_label(type)}: #{type[:name]}"
|
|
116
116
|
workflow_info = pgyer_helper.select_workflow_for_project(
|
|
117
117
|
project_id: app_info_obj["id"],
|
|
118
118
|
package_type: type[:package_type],
|
|
@@ -169,7 +169,7 @@ module Pindo
|
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
def select_types_interactive
|
|
172
|
-
puts "\n
|
|
172
|
+
puts "\n请选择要配置的绑定类型(安装包为工具,git 为工作流,可多选):"
|
|
173
173
|
puts DIVIDER
|
|
174
174
|
WORKFLOW_TYPES.each_with_index do |type, index|
|
|
175
175
|
puts " #{index + 1}. #{type[:name]}"
|
|
@@ -343,11 +343,20 @@ module Pindo
|
|
|
343
343
|
WORKFLOW_TYPES.each do |type|
|
|
344
344
|
workflow = config[type[:workflow_key]]
|
|
345
345
|
next if workflow.nil?
|
|
346
|
-
|
|
346
|
+
if type[:manage_type] == 'git'
|
|
347
|
+
puts " #{type[:name]}: 工作流: #{workflow['tab_name']} (ID: #{workflow['workflow_id']})"
|
|
348
|
+
else
|
|
349
|
+
puts " #{type[:name]}: 工具: #{workflow['tab_name']} (packageId: #{workflow['package_id']})"
|
|
350
|
+
end
|
|
347
351
|
end
|
|
348
352
|
puts DIVIDER
|
|
349
353
|
end
|
|
350
354
|
|
|
355
|
+
# 安装包类型绑定的是「工具」,Git 绑定的是「工作流」
|
|
356
|
+
def binding_label(type)
|
|
357
|
+
type[:manage_type] == 'git' ? '工作流' : '工具'
|
|
358
|
+
end
|
|
359
|
+
|
|
351
360
|
end
|
|
352
361
|
end
|
|
353
362
|
end
|
|
@@ -156,6 +156,7 @@ module Pindo
|
|
|
156
156
|
# 7. 所有验证通过
|
|
157
157
|
result[:valid] = true
|
|
158
158
|
result[:workflow_info] = {
|
|
159
|
+
package_id: workflow['package_id'].to_s,
|
|
159
160
|
workflow_id: workflow['workflow_id'],
|
|
160
161
|
tab_name: workflow['tab_name'],
|
|
161
162
|
package_name: workflow['package_name'],
|
|
@@ -166,6 +167,7 @@ module Pindo
|
|
|
166
167
|
if ENV['PINDO_DEBUG']
|
|
167
168
|
puts "[PINDO_DEBUG] ✓✓✓ 配置验证通过 (#{workflow_key})"
|
|
168
169
|
puts "[PINDO_DEBUG] 返回 valid=true,workflow_info:"
|
|
170
|
+
puts " package_id: #{result[:workflow_info][:package_id]}"
|
|
169
171
|
puts " workflow_id: #{result[:workflow_info][:workflow_id]}"
|
|
170
172
|
puts " tab_name: #{result[:workflow_info][:tab_name]}"
|
|
171
173
|
puts " manage_type: #{result[:workflow_info][:manage_type]}"
|
|
@@ -174,86 +176,44 @@ module Pindo
|
|
|
174
176
|
return result
|
|
175
177
|
end
|
|
176
178
|
|
|
177
|
-
#
|
|
179
|
+
# 为项目选择工作流(Git)或安装包工具(ipa/apk/zip/mac/exe)
|
|
180
|
+
#
|
|
181
|
+
# JPS V1.3.94 起,workflow/list 不再返回产物工作流;安装包入口改为项目的 packageTools,
|
|
182
|
+
# 因此非 git 类型一律从 project/detail 的 packageTools 中选择。
|
|
178
183
|
#
|
|
179
184
|
# @param project_id [String] 项目ID
|
|
180
185
|
# @param package_type [String] 包类型
|
|
181
186
|
# @param working_directory [String] 工作目录
|
|
182
|
-
# @param manage_type [String] 管理类型(默认为空,"git"
|
|
183
|
-
# @
|
|
187
|
+
# @param manage_type [String] 管理类型(默认为空,"git" 时选择 Git 工作流)
|
|
188
|
+
# @param workflow_name [String, nil] 按名称精确选择(Git 匹配 tabName;工具匹配 name、subtitle 或 name(subtitle))
|
|
189
|
+
# @return [Hash] 选择的工作流/工具信息(symbol key 结构)
|
|
184
190
|
def select_workflow_for_project(project_id:, package_type:, working_directory:, manage_type: "", workflow_name: nil)
|
|
185
|
-
|
|
191
|
+
if manage_type == "git"
|
|
192
|
+
return select_git_workflow_for_project(project_id: project_id, package_type: package_type, workflow_name: workflow_name)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
select_package_tool_for_project(project_id: project_id, package_type: package_type, workflow_name: workflow_name)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# 选择 Git 仓库工作流(仍通过 workflow/list 获取)
|
|
199
|
+
def select_git_workflow_for_project(project_id:, package_type: nil, workflow_name: nil)
|
|
186
200
|
Funlog.instance.fancyinfo_start("正在获取可用工作流...")
|
|
187
201
|
|
|
188
202
|
workflow_result = @pgyer_client.get_project_workflows(project_id: project_id)
|
|
189
|
-
|
|
190
203
|
if workflow_result.nil? || workflow_result['data'].nil?
|
|
191
204
|
raise Informative, "获取工作流列表失败"
|
|
192
205
|
end
|
|
193
206
|
|
|
194
207
|
workflows = workflow_result['data']
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
208
|
+
type_desc = 'Git 管理类型'
|
|
209
|
+
# 严格筛选 manage_type == "git",不降级到其它类型
|
|
210
|
+
display_workflows = workflows.select do |w|
|
|
211
|
+
(w['manageType'] == 'git') || (w['manage_type'] == 'git')
|
|
198
212
|
end
|
|
199
213
|
|
|
200
|
-
puts "package_type #{package_type} manage_type: #{manage_type}"
|
|
201
|
-
|
|
202
|
-
# 2. 根据 manage_type 或 package_type 过滤工作流
|
|
203
|
-
if manage_type == "git"
|
|
204
|
-
# manage_type 为 git 时,只筛选 manage_type == "git" 的工作流,不看 package_type
|
|
205
|
-
# 严格筛选,不包括 manage_type 为空或其他类型的工作流
|
|
206
|
-
filtered_workflows = workflows.select do |w|
|
|
207
|
-
(w['manageType'] == 'git') || (w['manage_type'] == 'git')
|
|
208
|
-
end
|
|
209
|
-
type_desc = 'Git 管理类型'
|
|
210
|
-
# manage_type == "git" 时严格使用筛选结果,不降级
|
|
211
|
-
display_workflows = filtered_workflows
|
|
212
|
-
else
|
|
213
|
-
# 按 package_type 过滤工作流
|
|
214
|
-
filtered_workflows = workflows.select do |w|
|
|
215
|
-
# 如果工作流有 packageType 字段,进行过滤
|
|
216
|
-
if w['packageType']
|
|
217
|
-
case package_type
|
|
218
|
-
when 'ipa'
|
|
219
|
-
w['packageType'] == 'ipa'
|
|
220
|
-
when 'apk'
|
|
221
|
-
w['packageType'] == 'apk'
|
|
222
|
-
when 'zip'
|
|
223
|
-
w['packageType'] == 'zip'
|
|
224
|
-
when 'mac'
|
|
225
|
-
w['packageType'] == 'mac'
|
|
226
|
-
when 'exe'
|
|
227
|
-
w['packageType'] == 'exe'
|
|
228
|
-
else
|
|
229
|
-
true
|
|
230
|
-
end
|
|
231
|
-
else
|
|
232
|
-
# 如果没有 packageType 字段,显示所有工作流
|
|
233
|
-
true
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
type_desc = case package_type
|
|
238
|
-
when 'ipa' then 'iOS IPA'
|
|
239
|
-
when 'apk' then 'Android APK'
|
|
240
|
-
when 'zip' then 'WebGL'
|
|
241
|
-
when 'mac' then 'macOS App'
|
|
242
|
-
when 'exe' then 'Windows EXE'
|
|
243
|
-
else package_type
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
# 非 git 模式:过滤结果即为候选。若为空则交由下方“没有找到匹配工作流”报错,
|
|
247
|
-
# 不再回退到全部工作流——否则会把其它类型的工作流误当作请求类型(写错 workflow_key)
|
|
248
|
-
display_workflows = filtered_workflows
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
# 过滤后再报数:只报总数会让人以为剩下的工作流被漏掉了,
|
|
252
|
-
# 实际是按 manage_type / package_type 筛掉的,两个数字一起给出才不歧义
|
|
253
214
|
Funlog.instance.fancyinfo_success("获取工作流列表成功,共 #{workflows.size} 个工作流,其中 #{type_desc} #{display_workflows.size} 个")
|
|
254
215
|
|
|
255
|
-
#
|
|
256
|
-
# 只接受完整精确匹配,不做子串模糊匹配,避免 "Production" 误命中 "Legacy Production Upload"。
|
|
216
|
+
# 指定 workflow_name 时只接受完整精确匹配(忽略大小写与首尾空格),不做子串模糊匹配
|
|
257
217
|
if workflow_name && !workflow_name.to_s.strip.empty? && !display_workflows.empty?
|
|
258
218
|
key_name = workflow_name.to_s.strip.downcase
|
|
259
219
|
name_matched = display_workflows.select do |w|
|
|
@@ -266,44 +226,23 @@ module Pindo
|
|
|
266
226
|
display_workflows = name_matched
|
|
267
227
|
end
|
|
268
228
|
|
|
269
|
-
# 3. 根据匹配数量决定选择方式
|
|
270
|
-
workflow = nil
|
|
271
|
-
|
|
272
229
|
if display_workflows.empty?
|
|
273
|
-
#
|
|
274
|
-
|
|
275
|
-
"没有找到匹配 #{type_desc} 的工作流,请在 JPS 后台创建 Git 类型工作流(项目ID: #{project_id})"
|
|
276
|
-
else
|
|
277
|
-
"没有找到匹配 #{type_desc} 的工作流,请在 JPS 后台配置(项目ID: #{project_id})"
|
|
278
|
-
end
|
|
279
|
-
raise Informative, error_msg
|
|
280
|
-
|
|
281
|
-
elsif display_workflows.size == 1
|
|
282
|
-
# 情况2: 只有1个匹配的工作流,自动选择
|
|
283
|
-
workflow = display_workflows.first
|
|
284
|
-
workflow_name = workflow['tabName'] || workflow['tab_name']
|
|
285
|
-
Funlog.instance.fancyinfo_success("自动选择唯一匹配的工作流: #{workflow_name}")
|
|
230
|
+
raise Informative, "没有找到匹配 #{type_desc} 的工作流,请在 JPS 后台创建 Git 类型工作流(项目ID: #{project_id})"
|
|
231
|
+
end
|
|
286
232
|
|
|
233
|
+
workflow = if display_workflows.size == 1
|
|
234
|
+
Funlog.instance.fancyinfo_success("自动选择唯一匹配的工作流: #{display_workflows.first['tabName'] || display_workflows.first['tab_name']}")
|
|
235
|
+
display_workflows.first
|
|
287
236
|
else
|
|
288
|
-
|
|
289
|
-
cli = HighLine.new
|
|
290
|
-
workflow_choices = display_workflows.map do |w|
|
|
237
|
+
choices = display_workflows.map do |w|
|
|
291
238
|
"#{w['tabName'] || w['tab_name']} (ID: #{w['id'] || w['workflow_id']})"
|
|
292
239
|
end
|
|
293
|
-
|
|
294
|
-
selected = cli.choose do |menu|
|
|
295
|
-
menu.prompt = "请选择 #{type_desc} 工作流:"
|
|
296
|
-
menu.choices(*workflow_choices)
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
# 提取选择的工作流
|
|
300
|
-
selected_index = workflow_choices.index(selected)
|
|
301
|
-
workflow = display_workflows[selected_index]
|
|
240
|
+
choose_from_menu(prompt: "请选择 #{type_desc} 工作流:", choices: choices, items: display_workflows)
|
|
302
241
|
end
|
|
303
242
|
|
|
304
|
-
# 4. 返回标准化的工作流信息
|
|
305
243
|
{
|
|
306
244
|
workflow_id: workflow['id'] || workflow['workflow_id'],
|
|
245
|
+
package_id: "",
|
|
307
246
|
tab_name: workflow['tabName'] || workflow['tab_name'],
|
|
308
247
|
package_name: workflow['packageName'] || workflow['package_name'] || workflow['tabName'] || workflow['tab_name'],
|
|
309
248
|
package_type: package_type,
|
|
@@ -311,96 +250,73 @@ module Pindo
|
|
|
311
250
|
}
|
|
312
251
|
end
|
|
313
252
|
|
|
314
|
-
#
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
# 2. tab_name 必须包含 "提交包"
|
|
318
|
-
#
|
|
319
|
-
# @param project_id [String] 项目ID
|
|
320
|
-
# @param package_type [String] 包类型(ipa/apk/zip/app)
|
|
321
|
-
# @return [Hash] 选择的工作流信息
|
|
322
|
-
def select_workflow_for_adhoc(project_id:, package_type:)
|
|
323
|
-
# 1. 从 JPS API 获取可用工作流列表
|
|
324
|
-
workflow_result = @pgyer_client.get_project_workflows(project_id: project_id)
|
|
253
|
+
# 选择安装包工具(来自 project/detail 的 packageTools)
|
|
254
|
+
def select_package_tool_for_project(project_id:, package_type:, workflow_name: nil)
|
|
255
|
+
Funlog.instance.fancyinfo_start("正在获取项目工具列表...")
|
|
325
256
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
end
|
|
257
|
+
tools = get_project_package_tools(project_id: project_id, package_type: package_type)
|
|
258
|
+
type_desc = package_type_desc(package_type)
|
|
329
259
|
|
|
330
|
-
|
|
260
|
+
Funlog.instance.fancyinfo_success("获取工具列表成功,#{type_desc} 工具共 #{tools.size} 个")
|
|
331
261
|
|
|
332
|
-
if
|
|
333
|
-
|
|
262
|
+
if workflow_name && !workflow_name.to_s.strip.empty? && !tools.empty?
|
|
263
|
+
tools = match_package_tools_by_name(tools: tools, name: workflow_name, type_desc: type_desc)
|
|
334
264
|
end
|
|
335
265
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if w['packageType']
|
|
339
|
-
case package_type
|
|
340
|
-
when 'ipa'
|
|
341
|
-
w['packageType'] == 'ipa'
|
|
342
|
-
when 'apk'
|
|
343
|
-
w['packageType'] == 'apk'
|
|
344
|
-
when 'zip'
|
|
345
|
-
w['packageType'] == 'zip'
|
|
346
|
-
when 'mac'
|
|
347
|
-
w['packageType'] == 'mac'
|
|
348
|
-
else
|
|
349
|
-
true
|
|
350
|
-
end
|
|
351
|
-
else
|
|
352
|
-
# 如果没有 packageType 字段,保留(后续通过名称筛选)
|
|
353
|
-
true
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
# 3. 第二层过滤:tab_name 必须包含 "提交包"
|
|
358
|
-
adhoc_workflows = filtered_by_type.select do |w|
|
|
359
|
-
tab_name = w['tabName'] || w['tab_name'] || ''
|
|
360
|
-
tab_name.include?('提交包')
|
|
266
|
+
if tools.empty?
|
|
267
|
+
raise Informative, "项目中没有可用的 #{type_desc} 工具,请到 JPS 项目的「工具」页新建(项目ID: #{project_id})"
|
|
361
268
|
end
|
|
362
269
|
|
|
363
|
-
if
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
270
|
+
tool = if tools.size == 1
|
|
271
|
+
Funlog.instance.fancyinfo_success("自动选择唯一匹配的工具: #{package_tool_display_name(tools.first)}")
|
|
272
|
+
tools.first
|
|
273
|
+
else
|
|
274
|
+
choices = tools.map { |t| "#{package_tool_display_name(t)} (版本数: #{t['packageCount'] || 0})" }
|
|
275
|
+
choose_from_menu(prompt: "请选择 #{type_desc} 工具:", choices: choices, items: tools)
|
|
367
276
|
end
|
|
368
277
|
|
|
369
|
-
|
|
370
|
-
|
|
278
|
+
package_tool_to_workflow_info(tool, package_type)
|
|
279
|
+
end
|
|
371
280
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
281
|
+
# 按名称精确匹配工具(忽略大小写与首尾空格):显示名 name(subtitle)、subtitle(原 tab 名)、name 任一相等
|
|
282
|
+
def match_package_tools_by_name(tools:, name:, type_desc:)
|
|
283
|
+
key = name.to_s.strip.downcase
|
|
284
|
+
matched = tools.select do |t|
|
|
285
|
+
[package_tool_display_name(t), t["subtitle"], t["name"]].any? { |v| v.to_s.strip.downcase == key }
|
|
286
|
+
end
|
|
287
|
+
if matched.empty?
|
|
288
|
+
available = tools.map { |t| package_tool_display_name(t) }.join('、')
|
|
289
|
+
raise Informative, "未找到名称精确匹配 \"#{name}\" 的 #{type_desc} 工具,可选: #{available}"
|
|
290
|
+
end
|
|
291
|
+
matched
|
|
292
|
+
end
|
|
379
293
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
294
|
+
# AdHoc 专用工具选择
|
|
295
|
+
# 筛选条件:packageType 匹配,且副标题(原 tab 名)或名称包含 "提交包"
|
|
296
|
+
#
|
|
297
|
+
# @param project_id [String] 项目ID
|
|
298
|
+
# @param package_type [String] 包类型(ipa/apk/zip/mac)
|
|
299
|
+
# @return [Hash] 选择的工具信息
|
|
300
|
+
def select_workflow_for_adhoc(project_id:, package_type:)
|
|
301
|
+
tools = get_project_package_tools(project_id: project_id, package_type: package_type)
|
|
302
|
+
adhoc_tools = tools.select do |t|
|
|
303
|
+
t["subtitle"].to_s.include?('提交包') || t["name"].to_s.include?('提交包')
|
|
304
|
+
end
|
|
385
305
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
306
|
+
if adhoc_tools.empty?
|
|
307
|
+
raise Informative, "未找到符合条件的 AdHoc 工具\n" \
|
|
308
|
+
"要求:packageType=#{package_type} 且副标题包含 '提交包'\n" \
|
|
309
|
+
"请到 JPS 项目的「工具」页检查"
|
|
310
|
+
end
|
|
390
311
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
312
|
+
tool = if adhoc_tools.size == 1
|
|
313
|
+
adhoc_tools.first
|
|
314
|
+
else
|
|
315
|
+
choices = adhoc_tools.map { |t| package_tool_display_name(t) }
|
|
316
|
+
choose_from_menu(prompt: "请选择 AdHoc 工具:", choices: choices, items: adhoc_tools)
|
|
394
317
|
end
|
|
395
318
|
|
|
396
|
-
|
|
397
|
-
{
|
|
398
|
-
workflow_id: workflow['id'] || workflow['workflow_id'],
|
|
399
|
-
tab_name: workflow['tabName'] || workflow['tab_name'],
|
|
400
|
-
package_type: workflow['packageType'] || package_type,
|
|
401
|
-
package_name: workflow['packageName'] || workflow['package_name'] || '',
|
|
402
|
-
manage_type: workflow['manageType'] || workflow['manage_type'] || ''
|
|
403
|
-
}
|
|
319
|
+
package_tool_to_workflow_info(tool, package_type)
|
|
404
320
|
end
|
|
405
321
|
|
|
406
322
|
# 获取 AdHoc 上传信息
|
|
@@ -463,19 +379,19 @@ module Pindo
|
|
|
463
379
|
raise Informative, "未找到项目: #{upload_proj_name},请检查项目名称是否正确"
|
|
464
380
|
end
|
|
465
381
|
|
|
466
|
-
# 4. 获取 AdHoc
|
|
382
|
+
# 4. 获取 AdHoc 工具(调用专用函数)
|
|
467
383
|
workflow_info = select_workflow_for_adhoc(
|
|
468
384
|
project_id: app_info_obj["id"],
|
|
469
385
|
package_type: package_type
|
|
470
386
|
)
|
|
471
387
|
|
|
472
388
|
unless workflow_info
|
|
473
|
-
raise Informative, "未能获取 AdHoc
|
|
389
|
+
raise Informative, "未能获取 AdHoc 工具信息"
|
|
474
390
|
end
|
|
475
391
|
|
|
476
|
-
# 5.
|
|
392
|
+
# 5. 输出最终选择的项目和工具
|
|
477
393
|
puts "\n✓ 项目: #{app_info_obj['projectName']}"
|
|
478
|
-
puts "✓
|
|
394
|
+
puts "✓ 工具: #{workflow_info[:tab_name]}"
|
|
479
395
|
|
|
480
396
|
# 6. 保存项目名称到实例变量
|
|
481
397
|
@proj_name = upload_proj_name
|
|
@@ -532,9 +448,10 @@ module Pindo
|
|
|
532
448
|
puts "[PINDO_DEBUG] 配置加载结果: valid=#{config_result[:valid]}" if ENV['PINDO_DEBUG']
|
|
533
449
|
|
|
534
450
|
if config_result[:valid]
|
|
451
|
+
is_git_config = manage_type.to_s == "git"
|
|
535
452
|
puts "\n使用 JPSBuildConfig.json 配置:"
|
|
536
453
|
puts " 项目: #{config_result[:project_name]}"
|
|
537
|
-
puts "
|
|
454
|
+
puts " #{is_git_config ? '工作流' : '工具'}: #{config_result[:workflow_info][:tab_name]}"
|
|
538
455
|
|
|
539
456
|
if ENV['PINDO_DEBUG']
|
|
540
457
|
puts "[PINDO_DEBUG] 配置详细信息:"
|
|
@@ -547,6 +464,27 @@ module Pindo
|
|
|
547
464
|
raise Informative, "JPS 未登录或登录已失效,请执行 pindo jps login 重新登录"
|
|
548
465
|
end
|
|
549
466
|
|
|
467
|
+
# 安装包配置只有 workflow_id(旧格式)时,换算成 package_id 并写回;
|
|
468
|
+
# 找不到对应工具则落到下方交互重选流程
|
|
469
|
+
unless is_git_config
|
|
470
|
+
migrated = migrate_legacy_workflow_info!(
|
|
471
|
+
config_path: config_path,
|
|
472
|
+
project_id: config_result[:project_id],
|
|
473
|
+
package_type: package_type,
|
|
474
|
+
workflow_info: config_result[:workflow_info]
|
|
475
|
+
)
|
|
476
|
+
if migrated.nil?
|
|
477
|
+
puts "旧工作流(ID: #{config_result[:workflow_info][:workflow_id]})未找到对应工具,将重新选择"
|
|
478
|
+
config_result[:valid] = false
|
|
479
|
+
# 项目已知,只需重选工具:走下方 --proj 非交互项目解析分支
|
|
480
|
+
proj_name = config_result[:project_name]
|
|
481
|
+
else
|
|
482
|
+
config_result[:workflow_info] = migrated
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
if config_result[:valid]
|
|
550
488
|
puts "[PINDO_DEBUG] 正在查找项目: #{config_result[:project_name]}" if ENV['PINDO_DEBUG']
|
|
551
489
|
lookup_bundle_id = resolve_lookup_bundle_id(
|
|
552
490
|
bundle_name: bundle_name,
|
|
@@ -740,9 +678,11 @@ module Pindo
|
|
|
740
678
|
|
|
741
679
|
def start_upload(app_info_obj:nil, ipa_file_upload:nil, description:nil, workflow_info:nil)
|
|
742
680
|
|
|
743
|
-
#
|
|
744
|
-
|
|
745
|
-
|
|
681
|
+
# 验证工具信息必传:package_id 优先,旧配置换算不到时才用 workflow_id 兼容
|
|
682
|
+
package_id = workflow_info && workflow_info[:package_id].to_s.strip
|
|
683
|
+
workflow_id = workflow_info && workflow_info[:workflow_id]
|
|
684
|
+
if workflow_info.nil? || (package_id.to_s.empty? && (workflow_id.nil? || workflow_id.to_s.empty?))
|
|
685
|
+
raise Informative, "缺少工具信息(package_id),请确保调用 prepare_upload 时传入了 package_type"
|
|
746
686
|
end
|
|
747
687
|
|
|
748
688
|
if !ipa_file_upload.nil? &&
|
|
@@ -901,13 +841,13 @@ module Pindo
|
|
|
901
841
|
|
|
902
842
|
puts attachFileUrls
|
|
903
843
|
|
|
904
|
-
|
|
905
|
-
upload_params = {
|
|
844
|
+
upload_params = build_package_upload_params(
|
|
906
845
|
description: description,
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
846
|
+
package_url: upload_res,
|
|
847
|
+
attach_file_urls: attachFileUrls,
|
|
848
|
+
package_id: package_id,
|
|
849
|
+
workflow_id: workflow_id
|
|
850
|
+
)
|
|
911
851
|
|
|
912
852
|
# 提交包信息到服务器
|
|
913
853
|
Funlog.instance.fancyinfo_start("正在提交包信息到服务器...")
|
|
@@ -926,7 +866,9 @@ module Pindo
|
|
|
926
866
|
if result_data && result_data["data"] && result_data["data"]["id"]
|
|
927
867
|
Funlog.instance.fancyinfo_success("提交包信息完成!")
|
|
928
868
|
else
|
|
929
|
-
error_msg = result_data&.dig('msg') || '未知错误'
|
|
869
|
+
error_msg = result_data&.dig('msg') || result_data&.dig('meta', 'message') || '未知错误'
|
|
870
|
+
hint = package_upload_error_hint(result_data)
|
|
871
|
+
error_msg = "#{error_msg}(#{hint})" if hint
|
|
930
872
|
Funlog.instance.fancyinfo_error("提交包信息失败: #{error_msg}")
|
|
931
873
|
raise Informative, "上传失败:未获取到有效的返回数据"
|
|
932
874
|
end
|
|
@@ -945,6 +887,37 @@ module Pindo
|
|
|
945
887
|
|
|
946
888
|
end
|
|
947
889
|
|
|
890
|
+
# 项目包上传错误码 → 处理提示
|
|
891
|
+
PACKAGE_UPLOAD_ERROR_HINTS = {
|
|
892
|
+
97931 => "未传 packageId,请重新执行 pindo jps config 绑定工具",
|
|
893
|
+
97992 => "packageId 与 workflowId 冲突,只应传 packageId",
|
|
894
|
+
97953 => "该工具不是安装包类型,不能走项目包上传"
|
|
895
|
+
}.freeze
|
|
896
|
+
|
|
897
|
+
# 组装项目包上传参数:packageId 与 workflowId 只传一个(同时传且不匹配会报 97992)
|
|
898
|
+
def build_package_upload_params(description:, package_url:, attach_file_urls:, package_id:, workflow_id:)
|
|
899
|
+
params = {
|
|
900
|
+
description: description,
|
|
901
|
+
packageUrl: package_url,
|
|
902
|
+
attachFileUrls: attach_file_urls
|
|
903
|
+
}
|
|
904
|
+
if !package_id.to_s.strip.empty?
|
|
905
|
+
params.merge(packageId: package_id.to_s.strip)
|
|
906
|
+
else
|
|
907
|
+
# 换算不到工具的旧配置:按 workflowId 兼容上传(JPS 长期兼容)
|
|
908
|
+
Funlog.instance.fancyinfo_warning("未绑定工具,按旧工作流ID兼容上传: #{workflow_id}")
|
|
909
|
+
params.merge(workflowId: workflow_id)
|
|
910
|
+
end
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
# 从上传返回体中取错误码提示(码可能在 code 或 meta.code)
|
|
914
|
+
def package_upload_error_hint(result_data)
|
|
915
|
+
return nil unless result_data.is_a?(Hash)
|
|
916
|
+
code = result_data['code'] || result_data.dig('meta', 'code')
|
|
917
|
+
return nil if code.nil?
|
|
918
|
+
PACKAGE_UPLOAD_ERROR_HINTS[code.to_i]
|
|
919
|
+
end
|
|
920
|
+
|
|
948
921
|
def package_windows_exe_for_upload(exe_file_upload)
|
|
949
922
|
windows_exe_path = File.expand_path(exe_file_upload)
|
|
950
923
|
windows_build_dir = File.dirname(windows_exe_path)
|
|
@@ -1435,6 +1408,67 @@ module Pindo
|
|
|
1435
1408
|
result&.dig("data")
|
|
1436
1409
|
end
|
|
1437
1410
|
|
|
1411
|
+
# 取项目下可上传的安装包工具(project/detail 的 packageTools)
|
|
1412
|
+
# 按 package_type 筛选,去掉已下架(lifecycle=deprecated)和缺 packageId 的,保持接口返回的排序
|
|
1413
|
+
#
|
|
1414
|
+
# @param project_id [String] 项目ID
|
|
1415
|
+
# @param package_type [String] 包类型(ipa/apk/zip/mac/exe)
|
|
1416
|
+
# @return [Array<Hash>] packageTools 原始项
|
|
1417
|
+
def get_project_package_tools(project_id:, package_type:)
|
|
1418
|
+
detail = get_project_detail(project_id: project_id)
|
|
1419
|
+
tools = detail.is_a?(Hash) ? detail["packageTools"] : nil
|
|
1420
|
+
return [] unless tools.is_a?(Array)
|
|
1421
|
+
|
|
1422
|
+
tools.select do |t|
|
|
1423
|
+
t.is_a?(Hash) &&
|
|
1424
|
+
t["packageType"].to_s.downcase == package_type.to_s.downcase &&
|
|
1425
|
+
t["lifecycle"].to_s != "deprecated" &&
|
|
1426
|
+
!t["packageId"].to_s.strip.empty?
|
|
1427
|
+
end
|
|
1428
|
+
end
|
|
1429
|
+
|
|
1430
|
+
# 工具显示名:name(subtitle),与 GoodUnityBuild 写入的 tab_name 保持一致
|
|
1431
|
+
def package_tool_display_name(tool)
|
|
1432
|
+
name = tool["name"].to_s
|
|
1433
|
+
subtitle = tool["subtitle"].to_s
|
|
1434
|
+
subtitle.strip.empty? ? name : "#{name}(#{subtitle})"
|
|
1435
|
+
end
|
|
1436
|
+
|
|
1437
|
+
# 工具 → workflow_info(沿用 symbol key 结构,调用方无需改动)
|
|
1438
|
+
def package_tool_to_workflow_info(tool, package_type)
|
|
1439
|
+
{
|
|
1440
|
+
package_id: tool["packageId"].to_s,
|
|
1441
|
+
workflow_id: tool["workflowId"], # 老工具才有;新工具为 nil,仅用于兼容
|
|
1442
|
+
tab_name: package_tool_display_name(tool),
|
|
1443
|
+
package_name: tool["name"],
|
|
1444
|
+
package_type: package_type,
|
|
1445
|
+
manage_type: "package",
|
|
1446
|
+
subtitle: tool["subtitle"],
|
|
1447
|
+
bundle_id: tool["bundleId"]
|
|
1448
|
+
}
|
|
1449
|
+
end
|
|
1450
|
+
|
|
1451
|
+
# 旧配置(只有 workflow_id、没有 package_id)换算成工具并写回配置文件
|
|
1452
|
+
# 已有 package_id → 原样返回、不发请求;只有 workflow_id → 在 packageTools 里按 workflowId 查找
|
|
1453
|
+
#
|
|
1454
|
+
# @return [Hash, nil] 换算后的 workflow_info;找不到对应工具返回 nil
|
|
1455
|
+
def migrate_legacy_workflow_info!(config_path:, project_id:, package_type:, workflow_info:)
|
|
1456
|
+
return workflow_info unless workflow_info[:package_id].to_s.strip.empty?
|
|
1457
|
+
return nil if workflow_info[:workflow_id].nil? || workflow_info[:workflow_id].to_s.empty?
|
|
1458
|
+
|
|
1459
|
+
tool = get_project_package_tools(project_id: project_id, package_type: package_type)
|
|
1460
|
+
.find { |t| t["workflowId"].to_s == workflow_info[:workflow_id].to_s }
|
|
1461
|
+
return nil if tool.nil?
|
|
1462
|
+
|
|
1463
|
+
new_info = package_tool_to_workflow_info(tool, package_type)
|
|
1464
|
+
config = JSON.parse(File.read(config_path))
|
|
1465
|
+
key = jps_workflow_key(package_type: package_type)
|
|
1466
|
+
config[key] = build_workflow_data(workflow_info: new_info, package_type: package_type)
|
|
1467
|
+
atomic_write(config_path, JSON.pretty_generate(config))
|
|
1468
|
+
puts "已将旧工作流(ID: #{workflow_info[:workflow_id]})换算为工具: #{new_info[:tab_name]}"
|
|
1469
|
+
new_info
|
|
1470
|
+
end
|
|
1471
|
+
|
|
1438
1472
|
PROJECT_PAGE_SIZE = 100
|
|
1439
1473
|
# 安全上限:最多翻 200 页(约 2 万项目),防止服务端异常(如忽略 pageNo 恒返满页)导致死循环
|
|
1440
1474
|
MAX_PROJECT_PAGES = 200
|
|
@@ -2210,7 +2244,7 @@ module Pindo
|
|
|
2210
2244
|
end
|
|
2211
2245
|
|
|
2212
2246
|
atomic_write(config_file, JSON.pretty_generate(config) + "\n")
|
|
2213
|
-
puts "已写入 JPSBuildConfig.json(#{entries.size}
|
|
2247
|
+
puts "已写入 JPSBuildConfig.json(#{entries.size} 项绑定)"
|
|
2214
2248
|
config
|
|
2215
2249
|
end
|
|
2216
2250
|
|
|
@@ -2252,10 +2286,34 @@ module Pindo
|
|
|
2252
2286
|
end
|
|
2253
2287
|
end
|
|
2254
2288
|
|
|
2255
|
-
#
|
|
2289
|
+
# 包类型 → 显示名
|
|
2290
|
+
def package_type_desc(package_type)
|
|
2291
|
+
case package_type
|
|
2292
|
+
when 'ipa' then 'iOS IPA'
|
|
2293
|
+
when 'apk' then 'Android APK'
|
|
2294
|
+
when 'zip' then 'WebGL'
|
|
2295
|
+
when 'mac' then 'macOS App'
|
|
2296
|
+
when 'exe' then 'Windows EXE'
|
|
2297
|
+
else package_type.to_s
|
|
2298
|
+
end
|
|
2299
|
+
end
|
|
2300
|
+
|
|
2301
|
+
# HighLine 菜单选择,返回 items 中与所选 choice 同下标的元素
|
|
2302
|
+
def choose_from_menu(prompt:, choices:, items:)
|
|
2303
|
+
cli = HighLine.new
|
|
2304
|
+
selected = cli.choose do |menu|
|
|
2305
|
+
menu.prompt = prompt
|
|
2306
|
+
menu.choices(*choices)
|
|
2307
|
+
end
|
|
2308
|
+
items[choices.index(selected)]
|
|
2309
|
+
end
|
|
2310
|
+
|
|
2311
|
+
# 构建单个工作流/工具的写入结构(与 GoodUnityBuild 共用的 JPSBuildConfig.json 格式)
|
|
2312
|
+
# 安装包工具:package_id 为上传依据,workflow_id 仅兼容(新工具为 nil);Git 工作流:package_id 为空串
|
|
2256
2313
|
def build_workflow_data(workflow_info:, package_type:)
|
|
2257
2314
|
{
|
|
2258
2315
|
"workflow_id" => workflow_info[:workflow_id],
|
|
2316
|
+
"package_id" => workflow_info[:package_id].to_s,
|
|
2259
2317
|
"tab_name" => workflow_info[:tab_name],
|
|
2260
2318
|
"package_type" => package_type,
|
|
2261
2319
|
"package_name" => workflow_info[:package_name],
|
|
@@ -2268,20 +2326,24 @@ module Pindo
|
|
|
2268
2326
|
# @param workflow [Hash] 工作流配置对象
|
|
2269
2327
|
# @return [Boolean] 是否有效
|
|
2270
2328
|
def workflow_valid?(workflow)
|
|
2271
|
-
return false
|
|
2329
|
+
return false unless workflow.is_a?(Hash)
|
|
2272
2330
|
|
|
2273
|
-
# 检查 workflow_id
|
|
2274
|
-
return false if workflow['workflow_id'].nil? || workflow['workflow_id'].to_s.empty?
|
|
2275
|
-
|
|
2276
|
-
# git 类型的 workflow 不需要 package_name(管理 git commit,不是包文件)
|
|
2277
|
-
# 其他类型的 workflow 需要 package_name
|
|
2278
2331
|
is_git_workflow = workflow['manage_type'] == 'git'
|
|
2279
|
-
|
|
2280
|
-
|
|
2332
|
+
has_workflow_id = !workflow['workflow_id'].nil? && !workflow['workflow_id'].to_s.empty?
|
|
2333
|
+
has_package_id = !workflow['package_id'].to_s.strip.empty?
|
|
2334
|
+
|
|
2335
|
+
if is_git_workflow
|
|
2336
|
+
# Git 工作流必须有 workflow_id,不需要 package_name
|
|
2337
|
+
return false unless has_workflow_id
|
|
2338
|
+
else
|
|
2339
|
+
# 安装包工具:package_id / workflow_id 有一个即可(只有 workflow_id 的旧配置在 prepare_upload 中换算)
|
|
2340
|
+
return false unless has_package_id || has_workflow_id
|
|
2341
|
+
return false if workflow['package_name'].nil? || workflow['package_name'].to_s.empty?
|
|
2281
2342
|
end
|
|
2282
2343
|
|
|
2283
2344
|
if ENV['PINDO_DEBUG']
|
|
2284
2345
|
puts "[PINDO_DEBUG] workflow_valid? 检查通过:"
|
|
2346
|
+
puts " package_id: #{workflow['package_id']}"
|
|
2285
2347
|
puts " workflow_id: #{workflow['workflow_id']}"
|
|
2286
2348
|
puts " manage_type: #{workflow['manage_type']}"
|
|
2287
2349
|
puts " is_git_workflow: #{is_git_workflow}"
|
|
@@ -2395,14 +2457,18 @@ module Pindo
|
|
|
2395
2457
|
end
|
|
2396
2458
|
|
|
2397
2459
|
# 8. Project ID 不变,检查工作流是否需要更新
|
|
2460
|
+
# 安装包按 package_id 比较(新工具 workflow_id 都是 nil);Git 按 workflow_id 比较
|
|
2398
2461
|
existing_workflow = existing_config[workflow_key]
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2462
|
+
changed = if manage_type.to_s == 'git'
|
|
2463
|
+
existing_workflow_id = existing_workflow.is_a?(Hash) ? existing_workflow['workflow_id'] : nil
|
|
2464
|
+
existing_workflow_id.to_s.empty? || existing_workflow_id.to_s != workflow_info[:workflow_id].to_s
|
|
2465
|
+
else
|
|
2466
|
+
existing_package_id = existing_workflow.is_a?(Hash) ? existing_workflow['package_id'] : nil
|
|
2467
|
+
existing_package_id.to_s.empty? || existing_package_id.to_s != workflow_info[:package_id].to_s
|
|
2468
|
+
end
|
|
2404
2469
|
|
|
2405
|
-
|
|
2470
|
+
if changed
|
|
2471
|
+
# 工作流/工具变更 → 更新对应的 workflow 和项目信息
|
|
2406
2472
|
puts "#{workflow_key} 变更,更新工作流配置"
|
|
2407
2473
|
existing_config[workflow_key] = new_workflow_data
|
|
2408
2474
|
existing_config["bundle_group_name"] = new_bundle_group_name
|
|
@@ -2412,7 +2478,7 @@ module Pindo
|
|
|
2412
2478
|
return
|
|
2413
2479
|
end
|
|
2414
2480
|
|
|
2415
|
-
# 9. Project ID
|
|
2481
|
+
# 9. Project ID 和工作流/工具都不变 → 不修改
|
|
2416
2482
|
puts "配置未变更,跳过保存" if ENV['PINDO_DEBUG']
|
|
2417
2483
|
end
|
|
2418
2484
|
end
|
|
@@ -7,6 +7,9 @@ module Pindo
|
|
|
7
7
|
class NugetUploadTask < NugetTask
|
|
8
8
|
|
|
9
9
|
DEFAULT_NUGET_BUCKET_NAME = 'nuget-resource'.freeze
|
|
10
|
+
# NuGet 登记项目:JPS「Unity 组件」项目
|
|
11
|
+
# (原「Nuget 组件库」5e6b36f61b614ed88086373ef874616c 已停止接收 NuGet 登记,返回 90006)
|
|
12
|
+
NUGET_PROJECT_ID = '1b9f111539ba4715abb2011fbfe46fd8'.freeze
|
|
10
13
|
|
|
11
14
|
attr_reader :nupkg_file
|
|
12
15
|
|
|
@@ -132,8 +135,8 @@ module Pindo
|
|
|
132
135
|
puts "✅ 登录成功"
|
|
133
136
|
puts
|
|
134
137
|
|
|
135
|
-
# 2. 使用固定的
|
|
136
|
-
nuget_project_id =
|
|
138
|
+
# 2. 使用固定的 NuGet 登记项目(Unity 组件)
|
|
139
|
+
nuget_project_id = NUGET_PROJECT_ID
|
|
137
140
|
puts
|
|
138
141
|
|
|
139
142
|
# 3. 上传文件到存储
|
|
@@ -177,13 +177,13 @@ module Pindo
|
|
|
177
177
|
|
|
178
178
|
workflow_name: OptionItem.new(
|
|
179
179
|
key: :workflow_name,
|
|
180
|
-
name: '
|
|
181
|
-
description: '
|
|
180
|
+
name: '工作流/工具名称',
|
|
181
|
+
description: '按名称精确选择 Git 工作流或安装包工具(工具可匹配 name、subtitle 或 name(subtitle)),用于同类型多个时消歧(非交互场景使用)',
|
|
182
182
|
type: String,
|
|
183
183
|
env_name: 'PINDO_JPS_WORKFLOW_NAME',
|
|
184
184
|
optional: true,
|
|
185
185
|
cacheable: false,
|
|
186
|
-
example: 'pindo jps config --proj=MyApp --type=ipa --workflow_name="iOS
|
|
186
|
+
example: 'pindo jps config --proj=MyApp --type=ipa --workflow_name="iOS提交包"'
|
|
187
187
|
)
|
|
188
188
|
}
|
|
189
189
|
end
|
data/lib/pindo/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pindo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.22.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- wade
|
|
@@ -536,7 +536,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
536
536
|
- !ruby/object:Gem::Version
|
|
537
537
|
version: 3.0.0
|
|
538
538
|
requirements: []
|
|
539
|
-
rubygems_version: 4.0.
|
|
539
|
+
rubygems_version: 4.0.10
|
|
540
540
|
specification_version: 4
|
|
541
541
|
summary: easy work
|
|
542
542
|
test_files: []
|