kk-git 0.2.7 → 0.2.9

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: 02b01e1d1b95887bc25d0063757a68ef24b8fb50f726822522cd34623063d381
4
- data.tar.gz: 2682460aca56a009107f79be35f60dd9746eeb691c1449be1ff361268734ad3f
3
+ metadata.gz: cf707ff92a149936ea729095e66789b1af70a80a5519a1b90f262ac9f9bfeaf5
4
+ data.tar.gz: 16527f8e79675fde491dfad46bc3bf853f43755c837364c905bf7e1839fef542
5
5
  SHA512:
6
- metadata.gz: fe0d795b321f3457a0da6391c03ec86669f632c18a851b830f30e1ce765edbf01e14160bcb5dd2960bd9ef87a47a3540a0e7ecbcce6bac45992475492bcd6ea1
7
- data.tar.gz: f54fa6384570117be64f4b72038f0699027d331e1ef69a31491e20aa798b5e6c0a72325b580b36f58e847317a92ad8234c7763b5f56f6484dc33f1eed9ea1797
6
+ metadata.gz: 47fe99e7a65c3e9eed0f3e6d2fb56ec47dfe2ab77daf775a8706c598e7ed20b7857adaa6256a122c28924fb677954cbf60d3eb6311f319456c914b93d1f69ce2
7
+ data.tar.gz: fb76a7efc708d33ec57b9309db3b79a278b146a47df37159f4acdb39ff7f3920fa14996c9c70b24ed7a68e238d6170953ccd9886b5085b0c5d6cef522cc7d01e
@@ -315,8 +315,8 @@ module KKGit
315
315
  return false if path.nil?
316
316
  path.start_with?('openspec/') ||
317
317
  path.match?(/\AREADME(\..+)?\z/i) ||
318
- path.match?(/\.(md|mdx|txt)\z/i)
319
- end
318
+ path.match?(/\.(md|mdx|txt|csv)\z/i)
319
+ end
320
320
 
321
321
  def self.ci_path?(path)
322
322
  return false if path.nil?
@@ -312,6 +312,18 @@ module KKGit
312
312
  raise Error, 'Set KK_GIT_YES=1 to confirm this commit'
313
313
  end
314
314
 
315
+ def fallback_commit_message(repo_dir: '.')
316
+ inferred = KKGit::CommitMessage.generate(repo_dir: repo_dir, mode: :all).to_s.strip
317
+ return inferred unless inferred.empty?
318
+
319
+ out, _err, ok = run_cmd('git', 'diff', '--cached', '--name-only', chdir: repo_dir)
320
+ names = ok ? out.split("\n").reject(&:empty?) : []
321
+ return 'chore(general): Update project' if names.empty?
322
+
323
+ label = File.basename(names.first)
324
+ names.length == 1 ? "chore(general): Update #{label}" : "chore(general): Update #{names.length} files"
325
+ end
326
+
315
327
  def commit_with_message!(message, repo_dir: '.')
316
328
  commit_args = amend? ? %w[commit --amend -F] : %w[commit -F]
317
329
 
@@ -352,6 +364,17 @@ module KKGit
352
364
  add_all!(repo_dir: repo_dir)
353
365
  ensure_no_sensitive_staged!(repo_dir: repo_dir)
354
366
 
367
+ # add 后可能已干净:假脏(换行归一化等)或 KK_GIT_ADD_PATHS 未覆盖到变更
368
+ if working_tree_clean?(repo_dir: repo_dir)
369
+ if status(remote: remote_name, branch: branch_name, repo_dir: repo_dir).needs_sync?
370
+ sync_with_remote!(remote_name, branch_name, repo_dir: repo_dir)
371
+ return :synced
372
+ end
373
+
374
+ puts 'No changes to commit or push'
375
+ return :noop
376
+ end
377
+
355
378
  message =
356
379
  if commit_message_generator
357
380
  commit_message_generator.call
@@ -359,6 +382,10 @@ module KKGit
359
382
  KKGit::CommitMessage.generate(repo_dir: repo_dir, mode: :all)
360
383
  end
361
384
  message = message.to_s.strip
385
+ if message.empty?
386
+ message = fallback_commit_message(repo_dir: repo_dir)
387
+ warn "Commit message inference empty; using fallback: #{message}"
388
+ end
362
389
  raise Error, 'Could not generate commit message from staged changes' if message.empty?
363
390
 
364
391
  confirm_commit!(message)
@@ -71,6 +71,20 @@ module KKGit
71
71
  warn e.message
72
72
  exit 1
73
73
  end
74
+
75
+ desc 'Auto commit/push, then semver tag (SKIP_TAG=1 or KK_GIT_AUTO_TAG=0 to skip)'
76
+ task :auto_commit_push_tag do
77
+ generator = lambda do
78
+ Rake::Task['git:auto_commit'].reenable
79
+ Rake::Task['git:auto_commit'].invoke
80
+ ENV['KK_GIT_COMMIT_MESSAGE'].to_s
81
+ end
82
+
83
+ KKGit::Release.auto_commit_push_and_tag!(commit_message_generator: generator)
84
+ rescue KKGit::GitOps::Error, ArgumentError => e
85
+ warn e.message
86
+ exit 1
87
+ end
74
88
  end
75
89
  end
76
90
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KKGit
4
- # Semver bump and git tag helpers (maintainer release flow).
4
+ # Semver bump and git tag helpers (maintainer release flow + consumer auto-tag).
5
5
  module Release
6
6
  VERSION_PATH = File.join(__dir__, 'version.rb').freeze
7
7
 
@@ -48,7 +48,7 @@ module KKGit
48
48
  end
49
49
 
50
50
  def semver_max(*versions)
51
- versions.compact.max_by { |v| v }
51
+ versions.compact.max
52
52
  end
53
53
 
54
54
  def tag_exists?(tag, repo_dir: '.')
@@ -74,6 +74,42 @@ module KKGit
74
74
  true
75
75
  end
76
76
 
77
+ # Strict repo tags only: vMAJOR.MINOR.PATCH with MAJOR < max_major (skips date tags like v2026.09.23).
78
+ # @return [Array<Array(Integer)>]
79
+ def list_repo_semver_versions(prefix: 'v', repo_dir: '.', max_major: 1999)
80
+ stdout, _stderr, ok = GitOps.run_cmd('git', 'tag', '--list', "#{prefix}*", chdir: repo_dir)
81
+ return [] unless ok
82
+
83
+ stdout.to_s.split("\n").filter_map do |t|
84
+ t = t.strip
85
+ next unless t.start_with?(prefix)
86
+
87
+ ver = parse_semver(t.delete_prefix(prefix))
88
+ next unless ver
89
+ next if ver[0] > max_major
90
+
91
+ ver
92
+ end
93
+ end
94
+
95
+ # Next tag from git history only (no version.rb / gem VERSION). For product repos.
96
+ # @return [String] e.g. "v1.0.1"
97
+ def next_repo_semver_tag(prefix: nil, bump: nil, repo_dir: '.', default_base: [1, 0, 0], max_major: 1999)
98
+ prefix ||= ENV.fetch('KK_GIT_TAG_PREFIX', 'v')
99
+ bump ||= ENV.fetch('KK_GIT_BUMP', 'patch')
100
+ raise ArgumentError, "bump must be major|minor|patch (got #{bump})" unless %w[major minor patch].include?(bump)
101
+
102
+ base = list_repo_semver_versions(prefix: prefix, repo_dir: repo_dir, max_major: max_major).max || default_base
103
+ version = base
104
+ 50.times do
105
+ version = bump_semver(version, bump)
106
+ candidate = "#{prefix}#{semver_to_s(version)}"
107
+ return candidate unless tag_exists?(candidate, repo_dir: repo_dir)
108
+ end
109
+
110
+ raise 'Failed to generate next repo semver tag: too many attempts'
111
+ end
112
+
77
113
  # @return [Array(String, String)] tag, version
78
114
  def next_tag_and_version(prefix: nil, bump: nil, repo_dir: '.')
79
115
  prefix ||= ENV.fetch('KK_GIT_TAG_PREFIX', 'v')
@@ -81,6 +117,7 @@ module KKGit
81
117
 
82
118
  latest_tag = latest_semver_tag(prefix: prefix, repo_dir: repo_dir)
83
119
  tag_version = latest_tag ? parse_semver(latest_tag.delete_prefix(prefix)) : nil
120
+ # Prefer strict repo tags when gem/file versions would pollute consumer repos.
84
121
  file_version = current_version_in_file || parse_semver(KKGit::VERSION)
85
122
 
86
123
  # version.rb already ahead of tags and tag not yet created → release that version
@@ -109,5 +146,63 @@ module KKGit
109
146
  out, err, ok = GitOps.run_cmd('git', 'push', push_target, tag, chdir: repo_dir)
110
147
  GitOps.ensure_ok!(ok, 'git push tag', stdout: out, stderr: err, repo_dir: repo_dir)
111
148
  end
149
+
150
+ def auto_tag_enabled?
151
+ return false if ENV['SKIP_TAG'] == '1'
152
+
153
+ ENV.fetch('KK_GIT_AUTO_TAG', '1') != '0'
154
+ end
155
+
156
+ # Commit + push, then create/push a semver tag when a new commit was made.
157
+ #
158
+ # - Product repos: leave bump_gem_version false (uses next_repo_semver_tag).
159
+ # - kk-git itself: bump_gem_version true (updates version.rb before commit).
160
+ #
161
+ # Env: KK_GIT_AUTO_TAG (default 1), SKIP_TAG=1, KK_GIT_BUMP, KK_GIT_TAG_PREFIX
162
+ #
163
+ # @return [Hash] keys :result (Symbol), :tag (String or nil)
164
+ def auto_commit_push_and_tag!(commit_message_generator: nil, repo_dir: '.', bump_gem_version: false)
165
+ GitOps.ensure_in_repo!(repo_dir: repo_dir)
166
+
167
+ head_before, _err, ok = GitOps.run_cmd('git', 'rev-parse', 'HEAD', chdir: repo_dir)
168
+ head_before = ok ? head_before.to_s.strip : ''
169
+
170
+ prepared_tag = nil
171
+ if bump_gem_version && auto_tag_enabled? && !GitOps.working_tree_clean?(repo_dir: repo_dir)
172
+ prepared_tag, new_version = next_tag_and_version(repo_dir: repo_dir)
173
+ bumped = update_version!(new_version)
174
+ puts((bumped ? "Version bumped to #{new_version}" : "Version already #{new_version}") +
175
+ ", preparing tag #{prepared_tag}")
176
+ end
177
+
178
+ result = GitOps.auto_commit_push!(
179
+ commit_message_generator: commit_message_generator,
180
+ repo_dir: repo_dir
181
+ )
182
+
183
+ head_after, _err2, ok2 = GitOps.run_cmd('git', 'rev-parse', 'HEAD', chdir: repo_dir)
184
+ head_after = ok2 ? head_after.to_s.strip : ''
185
+ new_commit = result == :committed_and_synced || (head_before != head_after && !head_after.empty?)
186
+
187
+ unless auto_tag_enabled?
188
+ puts 'SKIP_TAG/KK_GIT_AUTO_TAG=0 — not tagging' if ENV['SKIP_TAG'] == '1' || ENV['KK_GIT_AUTO_TAG'] == '0'
189
+ return { result: result, tag: nil }
190
+ end
191
+
192
+ unless new_commit
193
+ puts "No new commit (#{result}) — skip tag"
194
+ return { result: result, tag: nil }
195
+ end
196
+
197
+ tag = prepared_tag || next_repo_semver_tag(repo_dir: repo_dir)
198
+ if tag_exists?(tag, repo_dir: repo_dir)
199
+ puts "Tag #{tag} already exists — skip"
200
+ return { result: result, tag: nil }
201
+ end
202
+
203
+ create_and_push_tag!(tag, repo_dir: repo_dir)
204
+ puts "Tagged and pushed #{tag}"
205
+ { result: result, tag: tag }
206
+ end
112
207
  end
113
208
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KKGit
4
- VERSION = '0.2.7'
4
+ VERSION = '0.2.9'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kk-git
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - kk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-13 00:00:00.000000000 Z
11
+ date: 2026-11-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Generate Conventional Commits commit messages from current git changes
14
14
  (staged/worktree), designed for Rake/script usage.