pindo 5.14.4 → 5.14.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb15b2496f39d434ab25b2609b651779fc38187e56990a40f66aeee02411da83
4
- data.tar.gz: c0abb252891099cf6c45bda365737415d662b1d165bb027064779db171c0fbe0
3
+ metadata.gz: 60289998ea7be5f175400dbd6038a6aebe104095280ee7fe10aba1ea513d20f8
4
+ data.tar.gz: 1a4fddd44fa17a17716a4e55a9c3ad7df41fed6357934e2b179801779dd7a139
5
5
  SHA512:
6
- metadata.gz: 3271d2f0516402ea4ee3f8716fe6d1fd4c1d0c1bc46e39ac65ed9c2fb00cb9f707dc44485acafb3e26a28b03b9069681f8a8d31c891534d144de614b53befb42
7
- data.tar.gz: 170f1753ee18dd359dea8a8f918625f82a4cdbaf34ce0f4dcfc342492b5b3086296589ef650f942ca000772a033d796f7f7e949b20cc52c45deda55ae56cafe6
6
+ metadata.gz: 99b491f10a169e0aeac7fef944d969b48bfa8520a220f3705f4762e3643515dd9e978bef2f5d519abc3970dc29ca734d41d5d6532beb61157389a92aee562ff2
7
+ data.tar.gz: b806779564f476de930e152265f2b36a340bd0a1dc82a7d703d8a3789f162910991a2a50d26a5c9b5ae9da719ba9b61032d9b4c58eec6ab5360305213547a700
@@ -3,13 +3,80 @@ require 'uri'
3
3
  require 'json'
4
4
  require 'faraday'
5
5
  require 'pindo/base/aeshelper'
6
- require 'faraday/retry'
6
+ require 'typhoeus'
7
+ require 'typhoeus/adapters/faraday'
7
8
 
8
9
  module Pindo
9
-
10
10
 
11
- class HttpClient
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, # Retry a failed request up to 5 times
29
- interval: 0.5, # First retry after 0.5s
30
- backoff_factor: 2, # Double the delay for each subsequent retry
31
- interval_randomness: 0.5, # Specify "jitter" of up to 50% of interval
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
- config.request :retry, retry_options
36
- config.proxy = proxy_options.compact if proxy_options[:uri]
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
 
@@ -1,191 +1,354 @@
1
- require 'highline/import'
2
- require 'fileutils'
3
- require 'json'
1
+ require 'pindo/module/pgyer/pgyerhelper'
2
+ require 'pindo/module/task/task_manager'
3
+ require 'pindo/module/task/model/jps/jps_bind_package_task'
4
+ require 'pindo/options/options'
5
+ require 'pindo/options/groups/task_options'
4
6
 
5
7
  module Pindo
6
8
  class Command
7
9
  class Jps < Command
8
10
  class Bind < Jps
9
11
 
10
- self.summary = '将编译的包与工作流绑定'
12
+ self.summary = '绑定 Git commit 到已上传的项目包'
11
13
 
12
14
  self.description = <<-DESC
13
- 将编译的包与工作流绑定。
15
+ 绑定 Git commit 到已上传的 JPS 项目包。
14
16
 
15
- 支持功能:
17
+ 支持功能:
16
18
 
17
- * 绑定编译包到指定工作流
19
+ * 交互式选择包类型(IPA、APK、WebGL、macOS)
20
+ * 支持多选,一次绑定多个包
21
+ * 支持选择历史 commit(使用 --select 参数)
22
+ * 自动关联到当前 HEAD commit 记录
18
23
 
19
- * 管理包与工作流的关联关系
24
+ 使用示例:
20
25
 
21
- * 支持多个工作流配置
26
+ $ pindo jps bind # 交互式选择包类型和 commit
22
27
 
23
- * 自动验证绑定状态
28
+ $ pindo jps bind --proj=demo # 指定项目
24
29
 
25
- 使用示例:
30
+ $ pindo jps bind --select # 选择历史 commit
26
31
 
27
- $ pindo jps bind # 绑定当前目录的包到默认工作流
28
-
29
- $ pindo jps bind --proj=demo # 绑定指定项目到工作流
30
-
31
- $ pindo jps bind --workflow=release # 绑定到指定的工作流
32
-
33
- $ pindo jps bind --list # 列出所有可用的工作流
34
32
  DESC
35
33
 
36
34
  self.arguments = [
37
-
38
35
  ]
39
36
 
37
+ # 定义此命令使用的参数项
38
+ def self.option_items
39
+ @option_items ||= Pindo::Options::OptionGroup.merge(
40
+ Pindo::Options::JPSOptions.select(:proj),
41
+ Pindo::Options::TaskOptions.select(:select),
42
+ Pindo::Options::GitOptions.all
43
+ )
44
+ end
45
+
40
46
  def self.options
41
- [
42
- ['--proj', '指定要绑定的项目名称'],
43
- ['--workflow', '指定要绑定的工作流名称'],
44
- ['--list', '列出所有可用的工作流'],
45
- ['--unbind', '解除包与工作流的绑定'],
46
- ['--status', '查看当前绑定状态']
47
- ].concat(super)
47
+ option_items.map(&:to_claide_option).concat(super)
48
48
  end
49
49
 
50
50
  def initialize(argv)
51
- @args_proj_name = argv.option('proj')
52
- @args_workflow_name = argv.option('workflow')
53
- @args_list_flag = argv.flag?('list', false)
54
- @args_unbind_flag = argv.flag?('unbind', false)
55
- @args_status_flag = argv.flag?('status', false)
51
+ # 使用 Options 系统解析参数
52
+ @options = initialize_options(argv)
56
53
 
57
- super
58
- @additional_args = argv.remainder!
54
+ # JPS 参数
55
+ @args_proj_name = @options[:proj]
56
+
57
+ # Task 参数
58
+ @args_select_flag = @options[:select] || false
59
+
60
+ super(argv)
59
61
  end
60
62
 
61
63
  def validate!
62
64
  super
63
- if @args_list_flag || @args_status_flag
64
- # 列出或查看状态时不需要其他参数
65
+ end
66
+
67
+ def run
68
+ project_path = Dir.pwd
69
+
70
+ # 1. 如果启用 --select 参数,获取用户选择的 commit
71
+ selected_commit_info = nil
72
+ if @args_select_flag
73
+ selected_commit_info = select_git_commit(project_path)
74
+
75
+ if selected_commit_info.nil?
76
+ puts "未选择任何提交,已取消操作"
77
+ return
78
+ end
79
+
80
+ puts "\n已选择提交:"
81
+ puts " Commit ID: #{selected_commit_info[:commit_id][0..7]}"
82
+ puts " 时间: #{selected_commit_info[:commit_time]}"
83
+ puts " 描述: #{selected_commit_info[:commit_desc]}"
84
+ puts ""
85
+ end
86
+
87
+ # 2. 获取 JPS 配置(git workflow 信息)
88
+ pgyer_helper = PgyerHelper.share_instace
89
+ pgyer_helper.login
90
+
91
+ app_info_obj, git_workflow_info = pgyer_helper.prepare_upload(
92
+ working_directory: project_path,
93
+ proj_name: @args_proj_name,
94
+ package_type: "",
95
+ manage_type: "git"
96
+ )
97
+
98
+ if app_info_obj.nil?
99
+ raise Informative, "#{@args_proj_name} 错误,请输入正确的App代号名称"
100
+ end
101
+
102
+ project_id = app_info_obj["id"]
103
+
104
+ # 3. 让用户选择要绑定的包类型
105
+ selected_package_types = select_package_types
106
+ if selected_package_types.empty?
107
+ puts "未选择任何包类型,已取消操作"
65
108
  return
66
109
  end
67
110
 
68
- if @args_unbind_flag && @args_workflow_name.nil?
69
- help! '解除绑定时需要指定工作流名称'
111
+ # 4. 获取对应类型的最新包
112
+ app_version_list = get_latest_packages_by_types(pgyer_helper, project_id, selected_package_types)
113
+
114
+ if app_version_list.empty?
115
+ raise Informative, "未找到可绑定的项目包,请先上传包"
70
116
  end
71
- end
72
117
 
73
- def run
74
- if @args_list_flag
75
- list_workflows
76
- elsif @args_status_flag
77
- show_bind_status
78
- elsif @args_unbind_flag
79
- unbind_workflow
118
+ puts "\n找到以下项目包:"
119
+ app_version_list.each do |pkg|
120
+ puts " [#{pkg['nativePackageType']}] ID: #{pkg['id']}, Version: #{pkg['projectVersion']}, Build: #{pkg['build']}"
121
+ end
122
+ puts ""
123
+
124
+ # 5. 创建任务链
125
+ tasks = []
126
+
127
+ # Git 提交任务
128
+ process_type = Pindo::GitHandler.get_uncommitted_files_process_type(
129
+ project_dir: project_path,
130
+ interactive: true
131
+ )
132
+
133
+ git_commit_task = Pindo::TaskSystem::GitCommitTask.new(
134
+ project_path,
135
+ {
136
+ process_type: process_type,
137
+ commit_message: "build: jps bind 绑定前提交"
138
+ }
139
+ )
140
+ tasks << git_commit_task
141
+
142
+ # 创建绑定任务(一次绑定所有包)
143
+ bind_task = Pindo::TaskSystem::JPSBindPackageTask.new(
144
+ app_version_list, # 传入包列表
145
+ {
146
+ git_commit_id: selected_commit_info&.dig(:commit_id),
147
+ git_commit_time: selected_commit_info&.dig(:commit_time),
148
+ git_commit_desc: selected_commit_info&.dig(:commit_desc),
149
+ project_dir: project_path,
150
+ app_info_obj: app_info_obj,
151
+ workflow_info: git_workflow_info,
152
+ project_name: @args_proj_name
153
+ }
154
+ )
155
+ bind_task.dependencies << git_commit_task.id
156
+ tasks << bind_task
157
+
158
+ # 6. 执行任务
159
+ task_manager = Pindo::TaskSystem::TaskManager.instance
160
+ task_manager.clear_all
161
+ tasks.each { |task| task_manager.add_task(task) }
162
+ task_manager.start
163
+
164
+ # 7. 输出结果
165
+ report = task_manager.execution_report
166
+ if report[:success] > 0
167
+ puts "\n✅ 绑定完成! 成功绑定 #{app_version_list.size} 个包到 Git Workflow"
80
168
  else
81
- bind_to_workflow
169
+ raise Informative, "绑定失败"
82
170
  end
83
171
  end
84
172
 
85
173
  private
86
174
 
87
- def list_workflows
88
- puts "\n可用的工作流列表:"
89
- puts "─────────────────────────────"
90
-
91
- # TODO: 从配置或API获取工作流列表
92
- workflows = [
93
- { name: "dev", description: "开发环境工作流" },
94
- { name: "test", description: "测试环境工作流" },
95
- { name: "staging", description: "预发布环境工作流" },
96
- { name: "release", description: "正式发布工作流" }
175
+ # 交互式选择包类型
176
+ # @return [Array<String>] 选择的包类型数组
177
+ def select_package_types
178
+ puts "\n请选择要绑定的包类型(可多选):"
179
+ puts "━" * 60
180
+
181
+ package_types = [
182
+ { key: 'ipa', name: 'IPA (iOS)' },
183
+ { key: 'apk', name: 'APK (Android)' },
184
+ { key: 'webgl', name: 'WebGL (Web)' },
185
+ { key: 'macos', name: 'MACOS (macOS)' }
97
186
  ]
98
187
 
99
- workflows.each do |workflow|
100
- puts " #{workflow[:name].ljust(12)} - #{workflow[:description]}"
188
+ package_types.each_with_index do |type, index|
189
+ puts " #{index + 1}. #{type[:name]}"
101
190
  end
102
- puts "─────────────────────────────\n"
103
- end
191
+ puts " 0. 取消操作"
192
+ puts "━" * 60
104
193
 
105
- def show_bind_status
106
- puts "\n当前绑定状态:"
107
- puts "─────────────────────────────"
194
+ # 获取用户输入
195
+ print "\n请输入序号(多个用逗号分隔,如 1,2): "
196
+ input = $stdin.gets.strip
108
197
 
109
- # TODO: 从配置或API获取当前绑定状态
110
- proj_name = @args_proj_name || get_current_project_name
198
+ # 解析用户输入
199
+ if input == '0' || input.empty?
200
+ return []
201
+ end
111
202
 
112
- if proj_name
113
- puts " 项目名称: #{proj_name}"
114
- puts " 绑定状态: 已绑定"
115
- puts " 工作流: release"
116
- puts " 绑定时间: #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
117
- puts " 最后构建: #123"
203
+ selected = []
204
+ input.split(',').each do |num_str|
205
+ num = num_str.strip.to_i
206
+ if num > 0 && num <= package_types.size
207
+ selected << package_types[num - 1][:key]
208
+ end
209
+ end
210
+
211
+ if selected.empty?
212
+ puts "无效输入,未选择任何包类型"
118
213
  else
119
- puts " 当前没有绑定任何工作流"
214
+ puts "\n已选择: #{selected.join(', ')}"
120
215
  end
121
- puts "─────────────────────────────\n"
216
+
217
+ selected
122
218
  end
123
219
 
124
- def bind_to_workflow
125
- proj_name = @args_proj_name || get_current_project_name
126
- workflow_name = @args_workflow_name || "dev"
220
+ # 根据包类型获取最新的项目包列表
221
+ # @param pgyer_helper [PgyerHelper] JPS 客户端
222
+ # @param project_id [String] 项目 ID
223
+ # @param package_types [Array<String>] 包类型数组
224
+ # @return [Array<Hash>] 项目包信息列表
225
+ def get_latest_packages_by_types(pgyer_helper, project_id, package_types)
226
+ packages_to_bind = []
227
+
228
+ package_types.each do |package_type|
229
+ # 包类型映射:webgl -> zip
230
+ native_package_type = case package_type
231
+ when 'webgl'
232
+ 'zip'
233
+ else
234
+ package_type
235
+ end
127
236
 
128
- if proj_name.nil? || proj_name.empty?
129
- raise Informative, "无法确定项目名称,请使用 --proj 参数指定"
237
+ begin
238
+ # 获取项目包列表(只获取第一页的第一条)
239
+ result = pgyer_helper.instance_variable_get(:@pgyer_client).get_project_package_list(
240
+ projectId: project_id,
241
+ params: {
242
+ pageNo: 1,
243
+ pageSize: 1,
244
+ nativePackageType: native_package_type
245
+ }
246
+ )
247
+
248
+ # 兼容两种响应格式
249
+ packages = result&.dig("data") || result&.dig("data", "packages")
250
+
251
+ if packages && packages.is_a?(Array) && packages.any?
252
+ pkg = packages.first
253
+ # 添加原始类型标记
254
+ pkg['originalType'] = package_type
255
+ packages_to_bind << pkg
256
+ else
257
+ puts " ⚠️ 未找到 #{package_type} 类型的包"
258
+ end
259
+ rescue => e
260
+ Funlog.instance.fancyinfo_error("获取 #{package_type} 类型的项目包失败: #{e.message}")
261
+ end
130
262
  end
131
263
 
132
- puts "\n正在绑定包到工作流..."
133
- puts " 项目: #{proj_name}"
134
- puts " 工作流: #{workflow_name}"
264
+ packages_to_bind
265
+ end
135
266
 
136
- # TODO: 调用JPS API进行实际绑定
137
- # result = JpsClient.bind_workflow(
138
- # project: proj_name,
139
- # workflow: workflow_name
140
- # )
267
+ # 交互式选择 git commit
268
+ # @param project_path [String] 项目路径
269
+ # @return [Hash, nil] 包含 :commit_id, :commit_time, :commit_desc,或 nil(取消)
270
+ def select_git_commit(project_path)
271
+ # 1. 查找 git 根目录
272
+ git_root = Pindo::GitHandler.git_root_directory(local_repo_dir: project_path)
273
+ unless git_root
274
+ raise Informative, "当前目录不是 git 仓库"
275
+ end
141
276
 
142
- puts "\n✅ 绑定成功!"
143
- puts " 包 '#{proj_name}' 已成功绑定到工作流 '#{workflow_name}'"
144
- puts " 下次构建将自动触发该工作流"
145
- end
277
+ # 2. 获取最近 15 条 commit 历史
278
+ all_commits = get_recent_commits(git_root, limit: 15)
279
+
280
+ if all_commits.empty?
281
+ raise Informative, "未找到 git commit 历史"
282
+ end
283
+
284
+ # 3. 筛选符合规范的提交(以 feat:, fix: 等开头)
285
+ valid_prefixes = ['feat:', 'fix:', 'docs:', 'style:', 'refactor:', 'perf:', 'test:', 'build:', 'ci:', 'chore:', 'revert:']
286
+ commits = all_commits.select do |commit|
287
+ desc = commit[:commit_desc].to_s.strip
288
+ valid_prefixes.any? { |prefix| desc.downcase.start_with?(prefix) }
289
+ end
146
290
 
147
- def unbind_workflow
148
- proj_name = @args_proj_name || get_current_project_name
149
- workflow_name = @args_workflow_name
291
+ # 如果没有符合规范的提交,提示用户并使用全部提交
292
+ if commits.empty?
293
+ puts "\n警告:在最近15个提交中未找到符合规范的提交(feat:, fix: 等开头)"
294
+ puts "显示所有提交供您选择:"
295
+ commits = all_commits
296
+ else
297
+ puts "\n从最近15个提交中筛选出 #{commits.size} 个符合规范的提交:"
298
+ end
150
299
 
151
- if proj_name.nil? || proj_name.empty?
152
- raise Informative, "无法确定项目名称,请使用 --proj 参数指定"
300
+ # 4. 显示 commit 列表
301
+ puts "\n请选择要绑定的 git 提交:"
302
+ puts "━" * 80
303
+ commits.each_with_index do |commit, index|
304
+ puts "#{index + 1}. [#{commit[:commit_id][0..7]}] #{commit[:commit_time]} - #{commit[:commit_desc]}"
153
305
  end
306
+ puts "0. 取消操作"
307
+ puts "━" * 80
308
+
309
+ # 5. 获取用户选择
310
+ choice = nil
311
+ loop do
312
+ print "\n请输入序号 (0-#{commits.size}): "
313
+ input = $stdin.gets.strip
154
314
 
155
- puts "\n正在解除绑定..."
156
- puts " 项目: #{proj_name}"
157
- puts " 工作流: #{workflow_name}"
315
+ choice = input.to_i
316
+ break if choice >= 0 && choice <= commits.size
158
317
 
159
- # TODO: 调用JPS API进行解除绑定
160
- # result = JpsClient.unbind_workflow(
161
- # project: proj_name,
162
- # workflow: workflow_name
163
- # )
318
+ puts "无效输入,请输入 0-#{commits.size} 之间的数字"
319
+ end
164
320
 
165
- puts "\n✅ 解除绑定成功!"
166
- puts " 包 '#{proj_name}' 已从工作流 '#{workflow_name}' 解除绑定"
321
+ # 6. 返回选择的 commit(0 表示取消)
322
+ choice == 0 ? nil : commits[choice - 1]
167
323
  end
168
324
 
169
- def get_current_project_name
170
- # 尝试从当前目录获取项目名称
171
- current_dir = Dir.pwd
172
-
173
- # 1. 尝试从git仓库名获取
174
- if File.directory?(File.join(current_dir, ".git"))
175
- git_config = File.join(current_dir, ".git", "config")
176
- if File.exist?(git_config)
177
- config_content = File.read(git_config)
178
- if config_content =~ /url = .*[\/:]([^\/]+?)(?:\.git)?$/
179
- return $1
180
- end
325
+ # 获取最近的 git commits
326
+ # @param git_root [String] git 根目录
327
+ # @param limit [Integer] 获取的 commit 数量
328
+ # @return [Array<Hash>] commit 列表,每个元素包含 :commit_id, :commit_time, :commit_desc
329
+ def get_recent_commits(git_root, limit: 20)
330
+ Dir.chdir(git_root) do
331
+ # 使用 git log 获取 commit 历史
332
+ # 格式:commit_id|commit_time|commit_desc
333
+ output = `git log -#{limit} --format="%H|%ci|%s" 2>/dev/null`.strip
334
+
335
+ return [] if output.empty?
336
+
337
+ output.split("\n").map do |line|
338
+ parts = line.split('|', 3)
339
+ {
340
+ commit_id: parts[0],
341
+ commit_time: parts[1],
342
+ commit_desc: parts[2]
343
+ }
181
344
  end
182
345
  end
183
-
184
- # 2. 尝试从目录名获取
185
- File.basename(current_dir)
346
+ rescue => e
347
+ Funlog.instance.fancyinfo_error("获取 git commit 历史失败: #{e.message}")
348
+ []
186
349
  end
187
350
 
188
351
  end
189
352
  end
190
353
  end
191
- end
354
+ end
@@ -174,7 +174,7 @@ module Pindo
174
174
  # @return [Hash, nil] 包含 :commit_id, :commit_time, :commit_desc,或 nil(取消)
175
175
  def select_git_commit(project_path)
176
176
  # 1. 查找 git 根目录
177
- git_root = find_git_root(project_path)
177
+ git_root = Pindo::GitHandler.git_root_directory(local_repo_dir: project_path)
178
178
  unless git_root
179
179
  raise Informative, "当前目录不是 git 仓库"
180
180
  end
@@ -227,20 +227,6 @@ module Pindo
227
227
  choice == 0 ? nil : commits[choice - 1]
228
228
  end
229
229
 
230
- # 查找 git 根目录
231
- # @param path [String] 起始路径
232
- # @return [String, nil] git 根目录,未找到返回 nil
233
- def find_git_root(path)
234
- current = File.expand_path(path)
235
- while current != '/'
236
- if File.exist?(File.join(current, '.git'))
237
- return current
238
- end
239
- current = File.dirname(current)
240
- end
241
- nil
242
- end
243
-
244
230
  # 获取最近的 git commits
245
231
  # @param git_root [String] git 根目录
246
232
  # @param limit [Integer] 获取的 commit 数量