Class: Pindo::GitRepoHelper

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/pindo/module/build/git_repo_helper.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#temp_tag_decisionObject

Returns the value of attribute temp_tag_decision.



24
25
26
# File 'lib/pindo/module/build/git_repo_helper.rb', line 24

def temp_tag_decision
  @temp_tag_decision
end

Class Method Details

.share_instanceObject



27
28
29
# File 'lib/pindo/module/build/git_repo_helper.rb', line 27

def share_instance
  instance
end

Instance Method Details

#add_git_cliffconfig(project_path) ⇒ Object

添加 git-cliff 配置

Parameters:

  • project_path (String)

    项目路径



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/pindo/module/build/git_repo_helper.rb', line 55

def add_git_cliffconfig(project_path)
  temp_dir = Dir.pwd
  Funlog.instance.fancyinfo_start("添加日志变更git-cliff配置...")
  if Pindo::GitHandler.is_git_directory?(local_repo_dir: project_path)
    current_git_root_path = Pindo::GitHandler.git_root_directory(local_repo_dir: project_path)
    Dir.chdir(current_git_root_path)
    pindo_common_dir = clone_pindo_common_config_repo(force_delete:false)
    if File.exist?(File.join(pindo_common_dir, 'cliff.toml'))
      FileUtils.cp_r(File.join(pindo_common_dir, 'cliff.toml'), File.join(current_git_root_path, 'cliff.toml'))
    end
    Funlog.instance.fancyinfo_update("仓库添加git-cliff配置")
    # 不自动提交推送,因为后续会将 cliff.toml 和 .gitignore 一起提交
    check_gitignore(current_git_root_path, auto_commit_push: false)
    Funlog.instance.fancyinfo_update("仓库检查并添加.gitignore规则")
    Dir.chdir(current_git_root_path)
    current_branch = Pindo::GitHandler.git!(%W(-C #{current_git_root_path} rev-parse --abbrev-ref HEAD)).strip
    Pindo::GitHandler.git!(%W(-C #{current_git_root_path} add cliff.toml))
    # .gitignore 已由 check_gitignore 自动添加到暂存区,无需重复添加
    commit_message = "docs: 添加日志变更配置".encode('UTF-8')
    Pindo::GitHandler.git!(%W(-C #{current_git_root_path} commit -m #{commit_message}))
    Pindo::GitHandler.git!(%W(-C #{current_git_root_path} push origin #{current_branch}))
  else
    Funlog.instance.fancyinfo_error("当前目录不是git仓库,请在git仓库根目录下执行此命令")
    Dir.chdir(temp_dir)
    return
  end
  Funlog.instance.fancyinfo_success("日志变更git-cliff配置完成!")
  Dir.chdir(temp_dir)
end

#calculate_build_version(project_dir:, tag_prefix: 'v', create_tag_type: nil, version_increase_type: nil) ⇒ String

计算构建版本号

Parameters:

  • project_dir (String)

    项目目录

  • tag_prefix (String) (defaults to: 'v')

    tag前缀,默认 ‘v’

  • create_tag_type (Symbol) (defaults to: nil)

    创建tag类型

  • version_increase_type (Symbol) (defaults to: nil)

    版本号增加类型

Returns:

  • (String)

    构建版本号

Raises:

  • (ArgumentError)


283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/pindo/module/build/git_repo_helper.rb', line 283

def calculate_build_version(project_dir:, tag_prefix: 'v', create_tag_type: nil, version_increase_type: nil)
  raise ArgumentError, "项目目录不能为空" if project_dir.nil?

  # 设置默认值
  create_tag_type ||= Pindo::CreateTagType::NEW
  version_increase_type ||= Pindo::VersionIncreaseType::MINI

  # 获取当前版本号
  current_version = get_current_version_from_tag(
    project_dir: project_dir,
    tag_prefixes: [tag_prefix]
  )

  # 根据 create_tag_type 计算 build_version
  case create_tag_type
  when Pindo::CreateTagType::NONE, Pindo::CreateTagType::RECREATE
    # 不创建tag或重新创建当前tag,使用当前版本号
    current_version
  when Pindo::CreateTagType::NEW
    # 创建新tag,需要检查HEAD是否已有tag
    if head_has_version_tag?(project_dir: project_dir, tag_prefix: tag_prefix)
      # HEAD已有tag,不需要创建新tag,使用当前版本号
      Funlog.instance.fancyinfo_success("HEAD已存在tag,使用当前版本号: #{current_version}")
      current_version
    else
      # HEAD没有tag,根据 version_increase_type 计算新版本号
      # 解析版本号
      parts = current_version.split('.').map(&:to_i)
      major = parts[0] || 0
      minor = parts[1] || 0
      patch = parts[2] || 0

      case version_increase_type
      when Pindo::VersionIncreaseType::MAIN
        major += 1
        minor = 0
        patch = 0
      when Pindo::VersionIncreaseType::MINI
        minor += 1
        patch = 0
      when Pindo::VersionIncreaseType::PATCH
        patch += 1
      end

      new_version = "#{major}.#{minor}.#{patch}"
      Funlog.instance.fancyinfo_success("新的版本号是: #{new_version}")
      new_version
    end
  else
    current_version
  end
end

#check_check_and_install_cliff(project_path) ⇒ Object

检查并安装 git-cliff

Parameters:

  • project_path (String)

    项目路径



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/pindo/module/build/git_repo_helper.rb', line 34

def check_check_and_install_cliff(project_path)
  if Pindo::GitHandler.is_git_directory?(local_repo_dir: project_path)
    current_git_root_path = Pindo::GitHandler.git_root_directory(local_repo_dir: project_path)
    unless File.exist?(File.join(current_git_root_path, 'cliff.toml'))
      add_git_cliffconfig(current_git_root_path)
    end
  end

  begin
    if !system('which git-cliff > /dev/null 2>&1')
      puts "安装git-cliff..."
      install_gitcliff()
    end
  rescue
    Funlog.instance.fancyinfo_error("安装git-cliff出现错误")
    return
  end
end

#check_gitignore(git_root_dir, auto_commit_push: true) ⇒ Boolean

检查并写入 .gitignore 文件(不会重复添加规则)如果修改了文件,会自动执行 git add、commit 和 push

Parameters:

  • git_root_dir (String)

    Git 根目录

  • auto_commit_push (Boolean) (defaults to: true)

    是否自动提交并推送,默认 true

Returns:

  • (Boolean)

    返回是否修改了 .gitignore 文件



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/pindo/module/build/git_repo_helper.rb', line 103

def check_gitignore(git_root_dir, auto_commit_push: true)
  gitignore_path = File.join(git_root_dir, '.gitignore')
  file_modified = false

  # 定义要添加的gitignore规则数组
  ignore_rules = [
    'Temp',
    'Logs',
    'build_ios.log',
    'feishu.json',
    'CHANGELOG.md',
    'GoodPlatform/iOS/*',
    'GoodPlatform/Android/*',
    'GoodPlatform/BaseiOS/Unity/*',
    'GoodPlatform/BaseiOS/Pods/',
    'GoodPlatform/BaseiOS/build',
    'GoodPlatform/BaseiOS/config.json',
    'GoodPlatform/BaseiOS/Podfile.lock',
    'GoodPlatform/BaseAndroid/Unity/*',
    'GoodPlatform/BaseAndroid/build',
    'GoodPlatform/WebGL',
    'config.json',
    'Assets/Packages',
    'Assets/WebGLTemplates.meta',
    'Assets/WebGLTemplates/',
    'JPSMedia',
    'Packages/packages-lock.json'
  ]

  # 读取现有的gitignore内容
  existing_lines = []
  if File.exist?(gitignore_path)
    existing_lines = File.readlines(gitignore_path).map(&:strip)
  end

  # 过滤出需要添加的规则(不存在的)
  rules_to_add = ignore_rules.reject { |rule| existing_lines.include?(rule) }

  # 如果有需要添加的规则,则添加
  unless rules_to_add.empty?
    File.open(gitignore_path, 'a') do |f|
      # 检查是否已有Pindo标记,如果没有则添加
      pindo_marker = '# Added by Pindo (pindo_common_ignore_1.0.0)'
      f.puts("\n#{pindo_marker}") unless existing_lines.include?(pindo_marker.strip)

      # 添加每条新规则
      rules_to_add.each do |rule|
        f.puts(rule)
      end
    end

    # 标记文件已修改
    file_modified = true

    # 自动添加到 Git 暂存区、提交并推送
    if Pindo::GitHandler.is_git_directory?(local_repo_dir: git_root_dir)
      begin
        # 1. 添加到暂存区
        Pindo::GitHandler.git!(%W(-C #{git_root_dir} add .gitignore))
        Funlog.instance.fancyinfo_success("已自动添加 .gitignore 到 Git 暂存区")

        # 2. 如果需要,自动提交并推送
        if auto_commit_push
          # 获取当前分支
          current_branch = Pindo::GitHandler.git!(%W(-C #{git_root_dir} rev-parse --abbrev-ref HEAD)).strip

          # 提交
          commit_message = "chore: 更新 .gitignore 规则"
          Pindo::GitHandler.git!(%W(-C #{git_root_dir} commit -m #{commit_message}))
          Funlog.instance.fancyinfo_success("已自动提交 .gitignore 更改")

          # 推送到远程
          Pindo::GitHandler.git!(%W(-C #{git_root_dir} push origin #{current_branch}))
          Funlog.instance.fancyinfo_success("已自动推送 .gitignore 到远程仓库")
        end
      rescue => e
        Funlog.instance.fancyinfo_error("Git 操作失败: #{e.message}")
      end
    end
  end

  file_modified
end

#create_and_push_tag(project_dir:, tag_name:, tag_type:) ⇒ String?

创建并推送 Tag

Parameters:

  • project_dir (String)

    项目目录

  • tag_name (String)

    tag 名称(如 v1.2.0)

  • tag_type (Symbol)

    创建类型 (:new, :recreate, :none)

Returns:

  • (String, nil)

    创建的 tag 名称,或 nil(跳过时)

Raises:

  • (ArgumentError)


355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/pindo/module/build/git_repo_helper.rb', line 355

def create_and_push_tag(project_dir:, tag_name:, tag_type:)
  raise ArgumentError, "项目目录不能为空" if project_dir.nil?
  raise ArgumentError, "tag名称不能为空" if tag_name.nil? || tag_name.empty?

  case tag_type
  when Pindo::CreateTagType::NONE
    Funlog.instance.fancyinfo_success("跳过创建 Tag")
    return nil
  when Pindo::CreateTagType::RECREATE
    # 删除旧 tag(本地和远程)
    if Pindo::GitHandler.remote_tag_exists?(local_repo_dir: project_dir, tag_name: tag_name)
      Funlog.instance.fancyinfo_update("删除远程 Tag: #{tag_name}")
      Pindo::GitHandler.git!(%W(-C #{project_dir} push origin :refs/tags/#{tag_name}))
    end
    if Pindo::GitHandler.local_tag_exists?(local_repo_dir: project_dir, tag_name: tag_name)
      Funlog.instance.fancyinfo_update("删除本地 Tag: #{tag_name}")
      Pindo::GitHandler.git!(%W(-C #{project_dir} tag -d #{tag_name}))
    end
  when Pindo::CreateTagType::NEW
    local_exists = Pindo::GitHandler.local_tag_exists?(local_repo_dir: project_dir, tag_name: tag_name)
    remote_exists = Pindo::GitHandler.remote_tag_exists?(local_repo_dir: project_dir, tag_name: tag_name)

    # 如果 tag 在 HEAD 上,不需要重新创建
    if local_exists && Pindo::GitHandler.is_tag_at_head?(git_root_dir: project_dir, tag_name: tag_name)
      if !remote_exists
        # 本地存在且在 HEAD,但远程不存在,推送到远程
        Pindo::GitHandler.git!(%W(-C #{project_dir} push origin #{tag_name}))
        Funlog.instance.fancyinfo_success("推送 Tag 到远程: #{tag_name}")
      else
        Funlog.instance.fancyinfo_success("Tag 已存在且在 HEAD: #{tag_name}")
      end
      return tag_name
    end

    # tag 不在 HEAD 上,需要删除后重新创建
    if remote_exists
      Funlog.instance.fancyinfo_update("删除远程 Tag: #{tag_name}")
      Pindo::GitHandler.git!(%W(-C #{project_dir} push origin :refs/tags/#{tag_name}))
    end
    if local_exists
      Funlog.instance.fancyinfo_update("删除本地 Tag: #{tag_name}")
      Pindo::GitHandler.git!(%W(-C #{project_dir} tag -d #{tag_name}))
    end
    # 继续创建新 tag
  end

  # 创建并推送 tag
  Pindo::GitHandler.git!(%W(-C #{project_dir} tag #{tag_name}))
  Pindo::GitHandler.git!(%W(-C #{project_dir} push origin #{tag_name}))
  Funlog.instance.fancyinfo_success("创建并推送 Tag: #{tag_name}")
  tag_name
end

#get_build_number_from_commit(project_dir: nil) ⇒ Integer

获取Build号(从commit hash转换而来)

Parameters:

  • project_dir (String) (defaults to: nil)

    项目目录路径

Returns:

  • (Integer)

    Build号(6位16进制转10进制)

Raises:

  • (ArgumentError)


236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/pindo/module/build/git_repo_helper.rb', line 236

def get_build_number_from_commit(project_dir: nil)
  raise ArgumentError, "项目目录不能为空" if project_dir.nil?

  # 获取git根目录
  git_root = Pindo::GitHandler.git_root_directory(local_repo_dir: project_dir)
  return 1 unless git_root

  begin
    # 获取当前HEAD的commit hash前6位
    commit_hash = Pindo::GitHandler.git!(%W(-C #{git_root} rev-parse HEAD)).strip[0..5]

    # 将16进制转换为10进制
    build_number = commit_hash.to_i(16)

    # 确保在Android versionCode安全范围内(最大值为2^31-1)
    max_value = 2**31 - 1
    build_number = build_number % max_value if build_number > max_value

    # 确保build_number不为0
    build_number = 1 if build_number == 0

    build_number
  rescue StandardError => e
    Funlog.instance.fancyinfo_error("获取commit hash失败: #{e.message}")
    # 如果获取失败,返回基于时间戳的默认值
    Time.now.to_i % 1000000 + 1
  end
end

#get_current_version_from_tag(project_dir: nil, tag_prefixes: nil) ⇒ String

Returns 版本号(例如:1.2.0),如果没有tag则返回0.0.1.

Parameters:

  • project_dir (String) (defaults to: nil)

    项目目录路径

  • tag_prefixes (Array<String>) (defaults to: nil)

    可能的tag前缀列表,默认为 [“v”, “release”, “”]

Returns:

  • (String)

    版本号(例如:1.2.0),如果没有tag则返回0.0.1

Raises:

  • (ArgumentError)


191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/pindo/module/build/git_repo_helper.rb', line 191

def get_current_version_from_tag(project_dir: nil, tag_prefixes: nil)
  raise ArgumentError, "项目目录不能为空" if project_dir.nil?

  # 获取git根目录
  git_root = Pindo::GitHandler.git_root_directory(local_repo_dir: project_dir)
  return "0.0.1" unless git_root

  # 如果传入的前缀为空或nil,使用默认值
  prefixes = (tag_prefixes.nil? || tag_prefixes.empty?) ? ["v", "release", ""] : tag_prefixes

  # 尝试不同的tag前缀
  latest_tag = nil
  matched_prefix = nil
  prefixes.each do |prefix|
    latest_tag = Pindo::GitHandler.get_latest_version_tag(project_dir: git_root, tag_prefix: prefix)
    if latest_tag
      matched_prefix = prefix
      break
    end
  end

  return "0.0.1" if latest_tag.nil?

  # 从tag中提取版本号,移除匹配到的前缀
  version = if matched_prefix && !matched_prefix.empty?
    latest_tag.sub(/^#{Regexp.escape(matched_prefix)}/, '')
  else
    latest_tag
  end

  # 确保版本号格式正确(x.y.z)
  if version =~ /^\d+\.\d+\.\d+$/
    version
  elsif version =~ /^\d+\.\d+$/
    "#{version}.0"
  elsif version =~ /^\d+$/
    "#{version}.0.0"
  else
    "0.0.1"
  end
end

#head_has_version_tag?(project_dir:, tag_prefix: 'v') ⇒ Boolean

检查HEAD是否已有版本tag

Parameters:

  • project_dir (String)

    项目目录

  • tag_prefix (String) (defaults to: 'v')

    tag前缀

Returns:

  • (Boolean)

    HEAD是否有tag



340
341
342
343
344
345
346
347
348
# File 'lib/pindo/module/build/git_repo_helper.rb', line 340

def head_has_version_tag?(project_dir:, tag_prefix: 'v')
  latest_tag = Pindo::GitHandler.get_latest_version_tag(
    project_dir: project_dir,
    tag_prefix: tag_prefix
  )
  return false if latest_tag.nil?

  Pindo::GitHandler.is_tag_at_head?(git_root_dir: project_dir, tag_name: latest_tag)
end

#install_gitcliffObject

安装 git-cliff



86
87
88
89
90
91
92
93
94
95
# File 'lib/pindo/module/build/git_repo_helper.rb', line 86

def install_gitcliff
  puts "\n检查git-cliff命令是否安装"
  begin
    if !system('which git-cliff > /dev/null 2>&1')
      system('bash -c "$(curl -fsSL https://gitee.com/goodtools/env/raw/master/gitcliff_install.sh)"')
    end
  rescue
    Funlog.instance.fancyinfo_error("安装git-cliff出现错误")
  end
end

#valid_build_number?(build_number) ⇒ Boolean

验证Build号是否在有效范围内

Parameters:

  • build_number (Integer)

    Build号

Returns:

  • (Boolean)

    是否有效



270
271
272
273
274
275
# File 'lib/pindo/module/build/git_repo_helper.rb', line 270

def valid_build_number?(build_number)
  return false if build_number.nil?

  # Android versionCode的有效范围是1到2^31-1
  build_number >= 1 && build_number <= 2**31 - 1
end