pindo 5.14.8 → 5.15.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/aeshelper.rb +53 -22
  3. data/lib/pindo/base/git_handler.rb +243 -22
  4. data/lib/pindo/client/giteeclient.rb +15 -6
  5. data/lib/pindo/command/android/autobuild.rb +7 -5
  6. data/lib/pindo/command/appstore/autobuild.rb +5 -2
  7. data/lib/pindo/command/appstore/cert.rb +6 -0
  8. data/lib/pindo/command/ios/autobuild.rb +31 -21
  9. data/lib/pindo/command/ios/cert.rb +1 -1
  10. data/lib/pindo/command/jps/apptest.rb +1 -1
  11. data/lib/pindo/command/jps/bind.rb +6 -2
  12. data/lib/pindo/command/jps/media.rb +6 -2
  13. data/lib/pindo/command/jps/upload.rb +6 -4
  14. data/lib/pindo/command/repo/clone.rb +110 -32
  15. data/lib/pindo/command/repo/subgit.rb +91 -0
  16. data/lib/pindo/command/repo.rb +1 -0
  17. data/lib/pindo/command/unity/autobuild.rb +6 -4
  18. data/lib/pindo/command/unity/packbuild.rb +14 -7
  19. data/lib/pindo/command/utils/tag.rb +5 -3
  20. data/lib/pindo/command/web/autobuild.rb +7 -5
  21. data/lib/pindo/command.rb +1 -1
  22. data/lib/pindo/config/build_info_manager.rb +37 -14
  23. data/lib/pindo/module/appstore/bundleid_helper.rb +7 -3
  24. data/lib/pindo/module/build/git_repo_helper.rb +1 -14
  25. data/lib/pindo/module/cert/cert_helper.rb +33 -9
  26. data/lib/pindo/module/cert/xcode_cert_helper.rb +17 -7
  27. data/lib/pindo/module/pgyer/pgyerhelper.rb +110 -22
  28. data/lib/pindo/module/task/model/git/git_commit_task.rb +106 -6
  29. data/lib/pindo/module/task/model/git/git_tag_task.rb +17 -7
  30. data/lib/pindo/module/task/model/jps/jps_upload_media_task.rb +13 -8
  31. data/lib/pindo/module/task/model/resign/ipa_local_resign_task.rb +5 -0
  32. data/lib/pindo/options/core/option_item.rb +4 -5
  33. data/lib/pindo/options/groups/git_options.rb +40 -0
  34. data/lib/pindo/options/helpers/git_constants.rb +28 -0
  35. data/lib/pindo/version.rb +1 -1
  36. metadata +7 -5
@@ -32,13 +32,17 @@ module Pindo
32
32
  config_info[:bundle_id_extensionad] = app_info['app_identifier_extensionad']
33
33
  config_info[:bundle_id_watchapp] = app_info['app_identifier_watchapp']
34
34
  config_info[:bundle_id_watchapp_extension] = app_info['app_identifier_watchapp_extension']
35
+
36
+ # 从 app_info 提取 app_group_id(优先)
37
+ config_info[:group_id] = app_info['app_group_id']
38
+ config_info[:icloud_id] = app_info['app_icloud_id']
35
39
  end
36
40
 
37
- # 提取 App Group iCloud ID
41
+ # app_setting 提取(如果 app_info 中没有,则使用这里的配置)
38
42
  if config_json['app_setting']
39
43
  app_setting = config_json['app_setting']
40
- config_info[:group_id] = app_setting['app_group_id']
41
- config_info[:icloud_id] = app_setting['app_icloud_id']
44
+ config_info[:group_id] ||= app_setting['app_group_id']
45
+ config_info[:icloud_id] ||= app_setting['app_icloud_id']
42
46
  end
43
47
 
44
48
  config_info
@@ -2,22 +2,9 @@ require 'singleton'
2
2
  require 'pindo/base/git_handler'
3
3
  require 'pindo/base/executable'
4
4
  require 'highline/import'
5
+ require 'pindo/options/helpers/git_constants'
5
6
 
6
7
  module Pindo
7
- # 版本号增加类型常量(与 GitOptions::VERSION_INCREASE_TYPES 一致)
8
- module VersionIncreaseType
9
- MAIN = :main # 大版本号增加1 (x.0.0)
10
- MINI = :mini # 小版本号增加1 (0.x.0)
11
- PATCH = :patch # patch版本号增加1 (0.0.x)
12
- end
13
-
14
- # 创建Tag类型常量(与 GitOptions::CREATE_TAG_TYPES 一致)
15
- module CreateTagType
16
- NEW = :new # 创建新的tag,新的版本号
17
- RECREATE = :recreate # 重新创建当前版本号
18
- NONE = :none # 不创建版本号
19
- end
20
-
21
8
  class GitRepoHelper
22
9
  include Singleton
23
10
 
@@ -189,20 +189,29 @@ module Pindo
189
189
  decrypt_password = CertHelper.get_cached_password(cert_url)
190
190
  Funlog.instance.fancyinfo_start("正在安装证书...")
191
191
 
192
- cert_path = AESHelper.decrypt_specific_file(src_file: certs.first, password:decrypt_password, output_dir: output_dir)
193
- if cert_path.nil? || cert_path.empty? || !File.exist?(cert_path)
192
+ begin
193
+ cert_path = AESHelper.decrypt_specific_file(src_file: certs.first, password:decrypt_password, output_dir: output_dir)
194
+ rescue Informative => e
194
195
  AESHelper.delete_password(keychain_name:cert_url)
195
- # 清除内存中的密码缓存,避免重复使用错误密码
196
196
  @@password_cache.delete(cert_url)
197
- raise Informative, "证书解析失败,密码错误!"
197
+ raise Informative, "证书解析失败,已清除错误的密码,请重新运行输入正确的密码"
198
198
  end
199
199
 
200
- key_path = AESHelper.decrypt_specific_file(src_file: keys.first, password:decrypt_password, output_dir: output_dir)
201
- if key_path.nil? || key_path.empty? || !File.exist?(key_path)
200
+ begin
201
+ key_path = AESHelper.decrypt_specific_file(src_file: keys.first, password:decrypt_password, output_dir: output_dir)
202
+ rescue Informative => e
202
203
  AESHelper.delete_password(keychain_name:cert_url)
203
- # 清除内存中的密码缓存,避免重复使用错误密码
204
204
  @@password_cache.delete(cert_url)
205
- raise Informative, "证书解析失败,密码错误!"
205
+ raise Informative, "密钥解析失败,已清除错误的密码,请重新运行输入正确的密码"
206
+ end
207
+
208
+ # 解密成功,保存密码到 Keychain
209
+ begin
210
+ AESHelper.store_password(keychain_name: cert_url, password: decrypt_password)
211
+ Funlog.instance.fancyinfo_success("证书解密成功,密码已保存到Keychain")
212
+ rescue => e
213
+ Funlog.instance.fancyinfo_error("密码保存到Keychain失败: #{e.message}")
214
+ Funlog.instance.fancyinfo_error("下次使用时需要重新输入密码")
206
215
  end
207
216
 
208
217
  unless is_cert_valid?(cert_path)
@@ -272,9 +281,12 @@ module Pindo
272
281
  un_exist_files = []
273
282
  provisioning_info_array = []
274
283
 
275
- # 在循环外获取密码,避免重复添加到Keychain
284
+ # 在循环外获取密码
276
285
  decrypt_password = CertHelper.get_cached_password(cert_url)
277
286
 
287
+ # 标记是否已成功解密(用于判断是否保存密码)
288
+ decrypt_success = false
289
+
278
290
  bundle_id_map.each do |type, bundle_id_temp|
279
291
  profile_filename = File.join(certs_dir, "profiles", cert_sub_dir, [provision_start_name.to_s, bundle_id_temp].join('_') + provision_extension_name)
280
292
  unless File.exist?(profile_filename)
@@ -284,6 +296,7 @@ module Pindo
284
296
  # puts "正在安装 #{bundle_id_temp}..."
285
297
  output_dir = Dir.mktmpdir
286
298
  file_decrypt = AESHelper.decrypt_specific_file(src_file: profile_filename, password:decrypt_password, output_dir: output_dir)
299
+ decrypt_success = true # 标记至少有一个文件解密成功
287
300
  destpath = Provisioninghelper.install(file_decrypt)
288
301
  parsed_data = Provisioninghelper.parse(destpath)
289
302
 
@@ -301,6 +314,17 @@ module Pindo
301
314
  provisioning_info_array << provisioning_info
302
315
  end
303
316
 
317
+ # 如果有文件解密成功,保存密码到 Keychain
318
+ if decrypt_success
319
+ begin
320
+ AESHelper.store_password(keychain_name: cert_url, password: decrypt_password)
321
+ Funlog.instance.fancyinfo_success("Provisioning Profile 解密成功,密码已保存到Keychain")
322
+ rescue => e
323
+ Funlog.instance.fancyinfo_error("密码保存到Keychain失败: #{e.message}")
324
+ Funlog.instance.fancyinfo_error("下次使用时需要重新输入密码")
325
+ end
326
+ end
327
+
304
328
  Funlog.instance.fancyinfo_success("#{provision_start_name} #{platform_type} Provisioning Profiles文件安装完成!")
305
329
 
306
330
  if un_exist_files.size > 0
@@ -504,15 +504,25 @@ module Pindo
504
504
  certs_dir = Pindo::GitHandler.getcode_to_dir(reponame:cert_reponame, remote_url:cert_git_url, path: pindo_single_config.pindo_dir, new_branch:apple_id)
505
505
 
506
506
 
507
- keys = Dir[File.join(certs_dir, "certs", cert_sub_dir, "*.p12")]
507
+ keys = Dir[File.join(certs_dir, "certs", cert_sub_dir, "*.p12")]
508
508
  decrypt_password = Pindo::CertHelper.get_cached_password(cert_git_url)
509
509
  output_dir = Dir.mktmpdir
510
- key_path = AESHelper.decrypt_specific_file(src_file: keys.first, password:decrypt_password, output_dir: output_dir)
511
- if key_path.nil? || key_path.empty? || !File.exist?(key_path)
512
- AESHelper.delete_password(keychain_name:cert_git_url)
513
- # 清除内存中的密码缓存,避免重复使用错误密码
514
- Pindo::CertHelper.clear_password_cache_for_url(cert_git_url)
515
- raise Informative, "证书解析失败,密码错误!"
510
+ begin
511
+ key_path = AESHelper.decrypt_specific_file(src_file: keys.first, password:decrypt_password, output_dir: output_dir)
512
+ rescue Informative => e
513
+ AESHelper.delete_password(keychain_name:cert_git_url)
514
+ # 清除内存中的密码缓存,避免重复使用错误密码
515
+ Pindo::CertHelper.clear_password_cache_for_url(cert_git_url)
516
+ raise Informative, "密钥解析失败,已清除错误的密码,请重新运行输入正确的密码"
517
+ end
518
+
519
+ # 解密成功,保存密码到 Keychain
520
+ begin
521
+ AESHelper.store_password(keychain_name: cert_git_url, password: decrypt_password)
522
+ Funlog.instance.fancyinfo_success("密钥解密成功,密码已保存到Keychain")
523
+ rescue => e
524
+ Funlog.instance.fancyinfo_error("密码保存到Keychain失败: #{e.message}")
525
+ Funlog.instance.fancyinfo_error("下次使用时需要重新输入密码")
516
526
  end
517
527
 
518
528
  FileUtils.copy(key_path, File.join(cert_dest_dir, "#{cert_type_temp}.p12"))
@@ -56,6 +56,13 @@ module Pindo
56
56
  # - project_id [String] 项目ID
57
57
  # - workflow_info [Hash] 工作流信息(如果有效)
58
58
  def try_load_jps_build_config(working_directory:, package_type:, manage_type: "")
59
+ if ENV['PINDO_DEBUG']
60
+ puts "\n[PINDO_DEBUG] try_load_jps_build_config 调用:"
61
+ puts " working_directory: #{working_directory}"
62
+ puts " package_type: #{package_type.inspect}"
63
+ puts " manage_type: #{manage_type.inspect}"
64
+ end
65
+
59
66
  result = {
60
67
  valid: false,
61
68
  project_name: nil,
@@ -66,15 +73,23 @@ module Pindo
66
73
  # 1. 确定配置文件路径
67
74
  config_file = determine_config_file_path(working_directory)
68
75
 
76
+ if ENV['PINDO_DEBUG']
77
+ puts "[PINDO_DEBUG] 配置文件路径: #{config_file}"
78
+ puts "[PINDO_DEBUG] 文件存在: #{File.exist?(config_file)}"
79
+ end
80
+
69
81
  unless File.exist?(config_file)
70
- puts "[JPSConfig] 配置文件不存在" if ENV['DEBUG']
82
+ puts "[PINDO_DEBUG] ❌ 配置文件不存在,返回 valid=false" if ENV['PINDO_DEBUG']
83
+ puts "[JPSConfig] 配置文件不存在" if ENV['PINDO_DEBUG']
71
84
  return result
72
85
  end
73
86
 
74
87
  # 2. 读取并解析配置
75
88
  begin
76
89
  config = JSON.parse(File.read(config_file))
90
+ puts "[PINDO_DEBUG] ✓ 配置文件解析成功" if ENV['PINDO_DEBUG']
77
91
  rescue => e
92
+ puts "[PINDO_DEBUG] ❌ 配置文件解析失败: #{e.message}" if ENV['PINDO_DEBUG']
78
93
  puts "[JPSConfig] 配置文件解析失败: #{e.message}"
79
94
  return result
80
95
  end
@@ -83,9 +98,17 @@ module Pindo
83
98
  result[:project_name] = config['project_name']
84
99
  result[:project_id] = config['project_id']
85
100
 
101
+ if ENV['PINDO_DEBUG']
102
+ puts "[PINDO_DEBUG] 配置文件内容:"
103
+ puts " project_name: #{result[:project_name].inspect}"
104
+ puts " project_id: #{result[:project_id].inspect}"
105
+ puts " 配置keys: #{config.keys.inspect}"
106
+ end
107
+
86
108
  # 4. 验证项目ID
87
109
  if result[:project_id].nil? || result[:project_id].to_s.empty?
88
- puts "[JPSConfig] 项目ID为空" if ENV['DEBUG']
110
+ puts "[PINDO_DEBUG] 项目ID为空,返回 valid=false" if ENV['PINDO_DEBUG']
111
+ puts "[JPSConfig] 项目ID为空" if ENV['PINDO_DEBUG']
89
112
  return result
90
113
  end
91
114
 
@@ -95,7 +118,8 @@ module Pindo
95
118
  if manage_type == "git"
96
119
  # manage_type 为 git 时,直接使用 git_workflow
97
120
  workflow_key = 'git_workflow'
98
- puts "[JPSConfig] 使用 git_workflow 配置" if ENV['DEBUG']
121
+ puts "[PINDO_DEBUG] manage_type=git,使用 workflow_key='git_workflow'" if ENV['PINDO_DEBUG']
122
+ puts "[JPSConfig] 使用 git_workflow 配置" if ENV['PINDO_DEBUG']
99
123
  else
100
124
  # 按 package_type 查找
101
125
  workflow_key = case package_type
@@ -105,16 +129,25 @@ module Pindo
105
129
  when 'app' then 'macos_workflow'
106
130
  when 'exe' then 'win_workflow'
107
131
  else
132
+ puts "[PINDO_DEBUG] ❌ 不支持的 package_type: #{package_type}" if ENV['PINDO_DEBUG']
108
133
  puts "[JPSConfig] 不支持的 package_type: #{package_type}"
109
134
  return result
110
135
  end
136
+ puts "[PINDO_DEBUG] package_type=#{package_type},使用 workflow_key='#{workflow_key}'" if ENV['PINDO_DEBUG']
111
137
  end
112
138
 
113
139
  # 6. 验证工作流配置
114
140
  workflow = config[workflow_key]
115
141
 
142
+ if ENV['PINDO_DEBUG']
143
+ puts "[PINDO_DEBUG] 查找 workflow_key='#{workflow_key}'"
144
+ puts "[PINDO_DEBUG] workflow 存在: #{!workflow.nil?}"
145
+ puts "[PINDO_DEBUG] workflow 内容: #{workflow.inspect}" if workflow
146
+ end
147
+
116
148
  unless workflow_valid?(workflow)
117
- puts "[JPSConfig] #{workflow_key} 配置无效或不完整" if ENV['DEBUG']
149
+ puts "[PINDO_DEBUG] #{workflow_key} 配置无效或不完整,返回 valid=false" if ENV['PINDO_DEBUG']
150
+ puts "[JPSConfig] #{workflow_key} 配置无效或不完整" if ENV['PINDO_DEBUG']
118
151
  return result
119
152
  end
120
153
 
@@ -128,7 +161,14 @@ module Pindo
128
161
  manage_type: workflow['manage_type'] || ""
129
162
  }
130
163
 
131
- puts "[JPSConfig] 配置验证通过 (#{workflow_key})" if ENV['DEBUG']
164
+ if ENV['PINDO_DEBUG']
165
+ puts "[PINDO_DEBUG] ✓✓✓ 配置验证通过 (#{workflow_key})"
166
+ puts "[PINDO_DEBUG] 返回 valid=true,workflow_info:"
167
+ puts " workflow_id: #{result[:workflow_info][:workflow_id]}"
168
+ puts " tab_name: #{result[:workflow_info][:tab_name]}"
169
+ puts " manage_type: #{result[:workflow_info][:manage_type]}"
170
+ end
171
+ puts "[JPSConfig] 配置验证通过 (#{workflow_key})" if ENV['PINDO_DEBUG']
132
172
  return result
133
173
  end
134
174
 
@@ -204,7 +244,12 @@ module Pindo
204
244
 
205
245
  if display_workflows.empty?
206
246
  # 情况1: 没有匹配的工作流
207
- raise Informative, "没有找到匹配 #{type_desc} 的工作流"
247
+ error_msg = if manage_type == "git"
248
+ "没有找到匹配 #{type_desc} 的工作流,请在 JPS 后台创建 Git 类型工作流(项目ID: #{project_id})"
249
+ else
250
+ "没有找到匹配 #{type_desc} 的工作流,请在 JPS 后台配置(项目ID: #{project_id})"
251
+ end
252
+ raise Informative, error_msg
208
253
 
209
254
  elsif display_workflows.size == 1
210
255
  # 情况2: 只有1个匹配的工作流,自动选择
@@ -402,6 +447,14 @@ module Pindo
402
447
  end
403
448
 
404
449
  def prepare_upload(working_directory:nil, proj_name:nil, package_type:nil, manage_type: "")
450
+ if ENV['PINDO_DEBUG']
451
+ puts "\n[PINDO_DEBUG] prepare_upload 调用参数:"
452
+ puts " working_directory: #{working_directory}"
453
+ puts " proj_name: #{proj_name.inspect}"
454
+ puts " package_type: #{package_type.inspect}"
455
+ puts " manage_type: #{manage_type.inspect}"
456
+ end
457
+
405
458
  upload_proj_name = proj_name
406
459
  if upload_proj_name.nil? || upload_proj_name.empty?
407
460
  upload_proj_name = @proj_name
@@ -416,36 +469,54 @@ module Pindo
416
469
  end
417
470
 
418
471
  # 【核心优化】尝试从 JPSBuildConfig.json 加载配置
419
- if package_type
472
+ if package_type || manage_type
473
+ puts "[PINDO_DEBUG] 准备加载配置文件 (package_type=#{package_type.inspect}, manage_type=#{manage_type.inspect})" if ENV['PINDO_DEBUG']
474
+
420
475
  config_result = try_load_jps_build_config(
421
476
  working_directory: working_directory,
422
477
  package_type: package_type,
423
478
  manage_type: manage_type
424
479
  )
425
480
 
481
+ puts "[PINDO_DEBUG] 配置加载结果: valid=#{config_result[:valid]}" if ENV['PINDO_DEBUG']
482
+
426
483
  if config_result[:valid]
427
484
  # 配置有效,直接使用
428
485
  puts "\n使用 JPSBuildConfig.json 配置:"
429
486
  puts " 项目: #{config_result[:project_name]}"
430
487
  puts " 工作流: #{config_result[:workflow_info][:tab_name]}"
431
488
 
489
+ if ENV['PINDO_DEBUG']
490
+ puts "[PINDO_DEBUG] 配置详细信息:"
491
+ puts " project_name: #{config_result[:project_name]}"
492
+ puts " project_id: #{config_result[:project_id]}"
493
+ puts " workflow_info: #{config_result[:workflow_info].inspect}"
494
+ end
495
+
432
496
  # 确保已登录
433
497
  unless login
434
498
  raise Informative, "请先登录JPS网站"
435
499
  end
436
500
 
437
501
  # 获取完整的 app_info_obj
502
+ puts "[PINDO_DEBUG] 正在查找项目: #{config_result[:project_name]}" if ENV['PINDO_DEBUG']
438
503
  app_info_obj = find_app_info_with_obj_list(
439
504
  proj_name: config_result[:project_name]
440
505
  )
441
506
 
442
507
  if app_info_obj
508
+ puts "[PINDO_DEBUG] 项目找到,返回配置" if ENV['PINDO_DEBUG']
443
509
  @proj_name = config_result[:project_name]
444
510
  return app_info_obj, config_result[:workflow_info]
445
511
  else
512
+ puts "[PINDO_DEBUG] 配置的项目在 JPS 中不存在: #{config_result[:project_name]}" if ENV['PINDO_DEBUG']
446
513
  puts "配置的项目不存在,将重新选择"
447
514
  end
515
+ else
516
+ puts "[PINDO_DEBUG] 配置无效,进入交互选择流程" if ENV['PINDO_DEBUG']
448
517
  end
518
+ else
519
+ puts "[PINDO_DEBUG] 跳过配置加载(package_type 和 manage_type 都为空)" if ENV['PINDO_DEBUG']
449
520
  end
450
521
 
451
522
  # ===== 配置无效或不存在,进入用户选择流程 =====
@@ -463,8 +534,8 @@ module Pindo
463
534
  Pindo::Options::GlobalOptionsState.instance[:proj] = upload_proj_name
464
535
  end
465
536
 
466
- # 如果提供了 package_type,选择工作流并保存配置
467
- if package_type
537
+ # 如果提供了 package_type 或 manage_type,选择工作流并保存配置
538
+ if package_type || manage_type
468
539
  workflow_info = select_workflow_for_project(
469
540
  project_id: app_info_obj["id"],
470
541
  package_type: package_type,
@@ -589,8 +660,8 @@ module Pindo
589
660
  # 记录上次上传的项目
590
661
  PindoUserLocalConfig.instance.write_last_work_project(proj_name:app_info_obj["projectName"])
591
662
 
592
- # 如果提供了 package_type,选择工作流并保存配置
593
- if package_type
663
+ # 如果提供了 package_type 或 manage_type,选择工作流并保存配置
664
+ if package_type || manage_type
594
665
  workflow_info = select_workflow_for_project(
595
666
  project_id: app_info_obj["id"],
596
667
  package_type: package_type,
@@ -1415,11 +1486,11 @@ module Pindo
1415
1486
  # 根据 HEAD 是否有 tag 决定使用哪种参数
1416
1487
  cliff_args = if has_tag_at_head
1417
1488
  # HEAD 有 tag,输出最新 tag 的更改(相对于前一个 tag)
1418
- puts "HEAD 存在 tag: #{head_tag},使用 --latest 参数" if ENV['DEBUG']
1489
+ puts "HEAD 存在 tag: #{head_tag},使用 --latest 参数" if ENV['PINDO_DEBUG']
1419
1490
  "--latest"
1420
1491
  else
1421
1492
  # HEAD 没有 tag,输出未发布的更改(从最新 tag 到 HEAD)
1422
- puts "HEAD 不存在 tag,使用 --unreleased 参数" if ENV['DEBUG']
1493
+ puts "HEAD 不存在 tag,使用 --unreleased 参数" if ENV['PINDO_DEBUG']
1423
1494
  "--unreleased"
1424
1495
  end
1425
1496
 
@@ -1429,14 +1500,14 @@ module Pindo
1429
1500
  # 策略1: 使用项目根目录的 cliff.toml
1430
1501
  project_cliff_toml = File.join(current_git_root_path, "cliff.toml")
1431
1502
  if File.exist?(project_cliff_toml)
1432
- puts "使用项目配置文件: #{project_cliff_toml}" if ENV['DEBUG']
1503
+ puts "使用项目配置文件: #{project_cliff_toml}" if ENV['PINDO_DEBUG']
1433
1504
  cliff_config_cmd = "git-cliff -c \"#{project_cliff_toml}\" #{cliff_args} -o -"
1434
1505
  else
1435
1506
  # 策略2: 使用 Pindo 默认配置文件(直接从 Pindoconfig 获取目录,避免更新仓库)
1436
1507
  pindo_common_dir = Pindoconfig.instance.pindo_common_configdir
1437
1508
  pindo_cliff_toml = File.join(pindo_common_dir, 'cliff.toml')
1438
1509
  if File.exist?(pindo_cliff_toml)
1439
- puts "使用 Pindo 默认配置文件: #{pindo_cliff_toml}" if ENV['DEBUG']
1510
+ puts "使用 Pindo 默认配置文件: #{pindo_cliff_toml}" if ENV['PINDO_DEBUG']
1440
1511
  cliff_config_cmd = "git-cliff -c \"#{pindo_cliff_toml}\" #{cliff_args} -o -"
1441
1512
  end
1442
1513
  end
@@ -1451,20 +1522,20 @@ module Pindo
1451
1522
  description = stdout.strip
1452
1523
  # 如果有版本更新提示,输出到终端但不包含在描述中
1453
1524
  if stderr && !stderr.empty?
1454
- puts stderr if stderr.include?("new version") || ENV['DEBUG']
1525
+ puts stderr if stderr.include?("new version") || ENV['PINDO_DEBUG']
1455
1526
  end
1456
- puts "git-cliff 输出成功" if ENV['DEBUG']
1527
+ puts "git-cliff 输出成功" if ENV['PINDO_DEBUG']
1457
1528
  else
1458
1529
  Funlog.warning("git-cliff 执行失败,使用默认描述")
1459
1530
  error_msg = stderr && !stderr.empty? ? stderr : stdout
1460
- puts "错误信息: #{error_msg}" if ENV['DEBUG']
1531
+ puts "错误信息: #{error_msg}" if ENV['PINDO_DEBUG']
1461
1532
  # 使用默认描述而不是抛出异常
1462
1533
  description = "版本更新"
1463
1534
  end
1464
1535
  else
1465
1536
  # 没有找到任何配置文件
1466
1537
  Funlog.warning("未找到 cliff.toml 配置文件,使用默认描述")
1467
- if ENV['DEBUG']
1538
+ if ENV['PINDO_DEBUG']
1468
1539
  puts "请确保:"
1469
1540
  puts " 1. 项目根目录存在 cliff.toml 文件"
1470
1541
  puts " 2. 或 Pindo 工具目录存在默认配置文件"
@@ -1483,7 +1554,7 @@ module Pindo
1483
1554
  raise Informative, "git-cliff 未安装,无法生成版本描述"
1484
1555
  end
1485
1556
  else
1486
- puts "当前目录不是 git 仓库" if ENV['DEBUG']
1557
+ puts "当前目录不是 git 仓库" if ENV['PINDO_DEBUG']
1487
1558
  end
1488
1559
 
1489
1560
  return description
@@ -1832,8 +1903,25 @@ module Pindo
1832
1903
  # @return [Boolean] 是否有效
1833
1904
  def workflow_valid?(workflow)
1834
1905
  return false if workflow.nil?
1906
+
1907
+ # 检查 workflow_id
1835
1908
  return false if workflow['workflow_id'].nil? || workflow['workflow_id'].to_s.empty?
1836
- return false if workflow['package_name'].nil? || workflow['package_name'].empty?
1909
+
1910
+ # git 类型的 workflow 不需要 package_name(管理 git commit,不是包文件)
1911
+ # 其他类型的 workflow 需要 package_name
1912
+ is_git_workflow = workflow['manage_type'] == 'git'
1913
+ unless is_git_workflow
1914
+ return false if workflow['package_name'].nil? || workflow['package_name'].empty?
1915
+ end
1916
+
1917
+ if ENV['PINDO_DEBUG']
1918
+ puts "[PINDO_DEBUG] workflow_valid? 检查通过:"
1919
+ puts " workflow_id: #{workflow['workflow_id']}"
1920
+ puts " manage_type: #{workflow['manage_type']}"
1921
+ puts " is_git_workflow: #{is_git_workflow}"
1922
+ puts " package_name: #{workflow['package_name'].inspect}"
1923
+ end
1924
+
1837
1925
  true
1838
1926
  end
1839
1927
 
@@ -1951,7 +2039,7 @@ module Pindo
1951
2039
  end
1952
2040
 
1953
2041
  # 9. Project ID 和 Workflow ID 都不变 → 不修改
1954
- puts "配置未变更,跳过保存" if ENV['DEBUG']
2042
+ puts "配置未变更,跳过保存" if ENV['PINDO_DEBUG']
1955
2043
  end
1956
2044
  end
1957
2045
 
@@ -1,6 +1,7 @@
1
1
  require 'pindo/module/task/model/git_task'
2
2
  require 'pindo/base/git_handler'
3
3
  require 'pindo/module/build/git_repo_helper'
4
+ require 'pindo/options/helpers/git_constants'
4
5
 
5
6
  module Pindo
6
7
  module TaskSystem
@@ -36,7 +37,7 @@ module Pindo
36
37
  def initialize(project_path, options = {})
37
38
  # GitCommitTask 特有的属性
38
39
  @fixed_version = options[:fixed_version] # 外部指定的固定版本号
39
- @process_type = options[:process_type] || 'skip' # 默认跳过
40
+ @process_type = options[:process_type] || Pindo::UncommittedFilesProcessType::SKIP # 默认跳过
40
41
  @commit_message = options[:commit_message] || 'build: 构建产生提交' # 默认提交消息
41
42
 
42
43
  options[:project_path] = project_path
@@ -90,7 +91,7 @@ module Pindo
90
91
  begin
91
92
  Pindo::GitHandler.process_need_add_files(
92
93
  project_dir: root_dir,
93
- process_type: @process_type || 'skip',
94
+ process_type: @process_type || Pindo::UncommittedFilesProcessType::NONE,
94
95
  commit_message: @commit_message
95
96
  )
96
97
  rescue Pindo::Informative => e
@@ -104,10 +105,11 @@ module Pindo
104
105
 
105
106
  # 4. Stash 工作目录的残留修改(为分支同步做准备)
106
107
  stash_saved = false
108
+ stash_name = "pindo_stash_#{Time.now.strftime('%Y%m%d%H%M%S')}_#{rand(1000)}"
107
109
  status = Pindo::GitHandler.git!(%W(-C #{root_dir} status --porcelain)).strip
108
110
  unless status.empty?
109
- Funlog.instance.fancyinfo_update("工作目录有未提交更改,暂存到 stash")
110
- Pindo::GitHandler.git!(%W(-C #{root_dir} stash -u))
111
+ Funlog.instance.fancyinfo_update("工作目录有未提交更改,暂存到 stash: #{stash_name}")
112
+ Pindo::GitHandler.git!(%W(-C #{root_dir} stash push -u -m #{stash_name}))
111
113
  stash_saved = true
112
114
  end
113
115
 
@@ -150,11 +152,23 @@ module Pindo
150
152
  Funlog.instance.fancyinfo_success("Version: #{@build_version}, Build: #{@build_number}, Commit: #{commit_short}")
151
153
  end
152
154
 
155
+
153
156
  # 9. 还原 stash(如果之前有 stash)
154
157
  if stash_saved
155
158
  begin
156
- Pindo::GitHandler.git!(%W(-C #{root_dir} stash pop))
157
- Funlog.instance.fancyinfo_success("已还原 stash")
159
+ # 查找指定名字的 stash
160
+ stash_list = Pindo::GitHandler.git!(%W(-C #{root_dir} stash list)).strip
161
+ matched_line = stash_list.lines.find { |l| l.include?(stash_name) }
162
+
163
+ if matched_line && (stash_id = matched_line.match(/(stash@\{\d+\})/)&.[](1))
164
+ # 先应用 stash(不删除)
165
+ Pindo::GitHandler.git!(%W(-C #{root_dir} stash apply #{stash_id}))
166
+ # 应用成功后再删除 stash
167
+ Pindo::GitHandler.git!(%W(-C #{root_dir} stash drop #{stash_id}))
168
+ Funlog.instance.fancyinfo_success("已还原 stash: #{stash_name} (#{stash_id})")
169
+ else
170
+ Funlog.instance.fancyinfo_warning("未找到名为 #{stash_name} 的 stash,请手动检查")
171
+ end
158
172
  rescue => e
159
173
  Funlog.instance.fancyinfo_warning("stash 还原时发生冲突: #{e.message}")
160
174
  Funlog.instance.fancyinfo_warning("stash 已保留,请手动执行 'git stash pop' 处理冲突")
@@ -162,6 +176,10 @@ module Pindo
162
176
  end
163
177
  end
164
178
 
179
+
180
+ # 10. 显示主仓库和所有子仓库的 commit info
181
+ display_all_repos_commit_info(root_dir)
182
+
165
183
  {
166
184
  success: true,
167
185
  root_dir: root_dir,
@@ -169,6 +187,88 @@ module Pindo
169
187
  message: "Git 提交检查完成"
170
188
  }
171
189
  end
190
+
191
+ # ----------------------------------------------------
192
+ # 10. 显示主仓库和所有子仓库的 commit id 和 commit message
193
+ # ----------------------------------------------------
194
+ def display_all_repos_commit_info(root_dir)
195
+ Funlog.instance.fancyinfo_start("仓库及子模块 Commit 信息概览")
196
+
197
+ # 10.1 主仓库
198
+ begin
199
+ main_info = Pindo::GitHandler.git!(%W(-C #{root_dir} log -1 --format=%h|%s)).strip
200
+ main_id, main_msg = main_info.split('|', 2)
201
+ puts ""
202
+ puts " [Main Repo] #{File.basename(root_dir)}".green
203
+ puts " Commit: #{main_id} - #{main_msg}"
204
+ rescue => e
205
+ Funlog.instance.warning("获取主仓库信息失败: #{e.message}")
206
+ end
207
+
208
+ # 10.2 子模块
209
+ begin
210
+ # 使用 git submodule status 获取列表,更可靠
211
+ submodule_status_output = Pindo::GitHandler.git!(%W(-C #{root_dir} submodule status --recursive)).strip
212
+
213
+ unless submodule_status_output.empty?
214
+ puts ""
215
+ puts " [Submodules]".yellow
216
+ submodule_status_output.each_line do |line|
217
+ # line format: " 923... path/to/sub (v1.2)" or "-..." for uninitialized
218
+ parts = line.strip.split(' ')
219
+ next if parts.length < 2
220
+
221
+ clean_sha = parts[0].gsub(/^[-+U]/, '') # 去除状态前缀
222
+ short_sha = clean_sha[0..6]
223
+ sub_path = parts[1]
224
+ sub_abs_path = File.join(root_dir, sub_path)
225
+
226
+ # 只有当目录存在且是 git 仓库时才尝试读取 log
227
+ if File.directory?(sub_abs_path) && File.exist?(File.join(sub_abs_path, '.git'))
228
+ begin
229
+ # 使用 git show 指定 SHA 获取 message,避免 HEAD 指向不明的问题
230
+ raw_msg = Pindo::GitHandler.git!(%W(-C #{sub_abs_path} show -s --format=%s #{clean_sha}))
231
+ sub_msg = raw_msg.strip
232
+
233
+ # 处理编码问题:将 ASCII-8BIT 转换为 UTF-8,无效字符替换为 ?
234
+ if sub_msg.respond_to?(:force_encoding)
235
+ sub_msg.force_encoding("UTF-8")
236
+ unless sub_msg.valid_encoding?
237
+ sub_msg = sub_msg.encode("UTF-8", "binary", invalid: :replace, undef: :replace, replace: "?")
238
+ end
239
+ end
240
+
241
+ puts " • #{sub_path}: #{short_sha} - #{sub_msg}"
242
+ rescue => e
243
+ # 如果获取 log 失败,显示错误原因
244
+ puts " • #{sub_path}: #{short_sha} (获取Message失败: #{e.message.strip})"
245
+ end
246
+ else
247
+ # 未初始化或其他情况
248
+ status_char = parts[0][0] # 获取状态字符 (+, -, U, space)
249
+ status_desc = case status_char
250
+ when '-' then "未初始化"
251
+ when '+' then "版本不一致"
252
+ when 'U' then "合并冲突"
253
+ else "目录或.git不存在"
254
+ end
255
+ puts " • #{sub_path}: #{short_sha} (#{status_desc})"
256
+ end
257
+ end
258
+ end
259
+ rescue => e
260
+ # 忽略子模块错误
261
+ # Funlog.instance.warning("获取子模块信息异常: #{e.message}")
262
+ end
263
+
264
+ puts ""
265
+ Funlog.instance.fancyinfo_success("Commit 信息展示完成")
266
+ end
267
+
268
+ # 在 do_work 结束前调用
269
+ def do_work_end_hook(root_dir)
270
+ display_all_repos_commit_info(root_dir)
271
+ end
172
272
  end
173
273
  end
174
274
  end