ra10ke 4.5.1 → 4.6.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: e89462c238286812deefe1c66b23bd3458f10f68545f19394cda6e5cae239fa3
4
- data.tar.gz: be70614d1b793aaae4e3e9151186709b70d68506687b3a3590f6e79ed6fe4298
3
+ metadata.gz: a77b7170e6dfb723d530dc22553a16ca198a0b361ca3a2aac5169b05fb0e4c89
4
+ data.tar.gz: b8025d8e38a8051a8a3cf4baa8b214e74b96c8ea5230364a37b23ac22f210a61
5
5
  SHA512:
6
- metadata.gz: 95bbe0ab0fea1b2598c75f4e0f7cfee5c1b77acc457574bd55627bd584d9a9ae2b0360f6bb70fcafb8b4df03559b05d63db2ee5abc1f8364276e126ddfaae047
7
- data.tar.gz: 0c1d340000c757922d5929b27f61d814c4d7a1b8c1c7220d2a4bd50ba30f42c66bec026eb959bb03b74169ff567a6ec409a0c0c2ac357aa5744e86fbe2dce287
6
+ metadata.gz: 0047a09a069462ef4d25e9778b83558aa29e9c282106e1f32eafd1fcc87df65d25e31fb9becccfa4d4ae47e4b61d930dafc15fcd56cd56b4669801675c3c415f
7
+ data.tar.gz: 4d809b1fa050a40ab3e1a265999eb47c1eb337609586b06c87b7fa3537303e42721a6d8ad8c84bd3264d2b0a183e3f2a91334054520730b39bde47193fc346de
@@ -0,0 +1,5 @@
1
+ ---
2
+ skip-changelog:
3
+ - head-branch:
4
+ - '^release-*'
5
+ - '^rel[0-9]+'
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: 🏷️ Pull Request Labeler
3
+
4
+ on:
5
+ - pull_request_target
6
+
7
+ permissions: {}
8
+
9
+ jobs:
10
+ labeler:
11
+ name: Labeler
12
+ runs-on: ubuntu-latest
13
+ if: github.repository_owner == 'voxpupuli' || github.repository_owner == 'OpenVoxProject'
14
+ permissions:
15
+ pull-requests: write
16
+ steps:
17
+ - uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0
@@ -15,7 +15,7 @@ jobs:
15
15
  name: Build the gem
16
16
  runs-on: ubuntu-24.04
17
17
  steps:
18
- - uses: actions/checkout@v6
18
+ - uses: actions/checkout@v7
19
19
  - name: Install Ruby
20
20
  uses: ruby/setup-ruby@v1
21
21
  with:
@@ -76,7 +76,7 @@ jobs:
76
76
  uses: actions/download-artifact@v8
77
77
  with:
78
78
  name: gem-artifact
79
- - uses: rubygems/configure-rubygems-credentials@v2.0.0
79
+ - uses: rubygems/configure-rubygems-credentials@v2.1.0
80
80
  - name: Publish gem to rubygems.org
81
81
  shell: bash
82
82
  run: gem push *.gem
@@ -16,7 +16,7 @@ jobs:
16
16
  outputs:
17
17
  ruby: ${{ steps.ruby.outputs.versions }}
18
18
  steps:
19
- - uses: actions/checkout@v6
19
+ - uses: actions/checkout@v7
20
20
  - name: Install Ruby ${{ matrix.ruby }}
21
21
  uses: ruby/setup-ruby@v1
22
22
  with:
@@ -35,7 +35,7 @@ jobs:
35
35
  ruby: ${{ fromJSON(needs.rubocop_and_matrix.outputs.ruby) }}
36
36
  name: Ruby ${{ matrix.ruby }}
37
37
  steps:
38
- - uses: actions/checkout@v6
38
+ - uses: actions/checkout@v7
39
39
  - name: Install Ruby ${{ matrix.ruby }}
40
40
  uses: ruby/setup-ruby@v1
41
41
  with:
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [v4.6.0](https://github.com/voxpupuli/ra10ke/tree/v4.6.0) (2026-10-13)
6
+
7
+ [Full Changelog](https://github.com/voxpupuli/ra10ke/compare/v4.5.1...v4.6.0)
8
+
9
+ **Implemented enhancements:**
10
+
11
+ - feat: use git-gem in git\_repo class; drop support for git-gem version v1.x [\#152](https://github.com/voxpupuli/ra10ke/pull/152) ([rwaffen](https://github.com/rwaffen))
12
+
5
13
  ## [v4.5.1](https://github.com/voxpupuli/ra10ke/tree/v4.5.1) (2026-05-11)
6
14
 
7
15
  [Full Changelog](https://github.com/voxpupuli/ra10ke/compare/v4.5.0...v4.5.1)
@@ -165,8 +165,7 @@ module Ra10ke::Dependencies
165
165
  "https://#{::Regexp.last_match(1)}/#{::Regexp.last_match(2)}"
166
166
  end
167
167
  repo = ::Ra10ke::GitRepo.new(source_url)
168
- ref = repo.get_ref_like(mod.expected_version)
169
- ref_name = ref ? ref[:name] : "bad url or tag #{mod.expected_version} is missing"
168
+ ref_name = repo.get_ref_like(mod.expected_version) || "bad url or tag #{mod.expected_version} is missing"
170
169
  <<~EOF
171
170
  mod '#{mod.name}',
172
171
  :git => '#{source_url}',
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'tempfile'
3
+ require 'git'
4
+ require 'tmpdir'
4
5
 
5
6
  module Ra10ke
6
7
  class GitRepo
7
8
  attr_reader :url
8
9
 
9
- REMOTE_REFS_CMD = 'git ls-remote --symref'
10
- CLONE_CMD = 'git clone --no-tags'
11
- CURRENT_BRANCH_CMD = 'git symbolic-ref --short HEAD'
12
- SHOW_CMD = 'git show'
13
-
14
10
  def initialize(url)
15
11
  @url = url
16
12
  end
@@ -19,18 +15,19 @@ module Ra10ke
19
15
  # @param path [String] - The path to the repository to check
20
16
  # @return [String] - The current active branch of the Git repo
21
17
  def self.current_branch(path)
22
- Dir.chdir(path) do
23
- data, success = run_command(CURRENT_BRANCH_CMD)
24
- return success ? data.strip : nil
25
- end
18
+ branch = Git.open(path).current_branch
19
+ branch unless branch == 'HEAD' || branch.to_s.empty?
20
+ rescue Git::Error, ArgumentError
21
+ nil
26
22
  end
27
23
 
28
- # @return [Array] - the raw data from the git ls-remote command as lines array
29
- # return empty array if url or command failed
24
+ # @return [Hash] - remote refs grouped by the git gem
25
+ # return empty hash if the command failed
30
26
  def remote_refs
31
27
  @remote_refs ||= begin
32
- data, success = run_command("#{REMOTE_REFS_CMD} #{url}")
33
- success ? data.lines : []
28
+ Git.ls_remote(url)
29
+ rescue Git::Error
30
+ {}
34
31
  end
35
32
  end
36
33
 
@@ -39,89 +36,55 @@ module Ra10ke
39
36
  !remote_refs.empty?
40
37
  end
41
38
 
42
- # @return [Boolean] - return true if the commit sha is valid
43
- # @param url [String] - the git string either https or ssh url
44
- # @param ref [String] - the sha id
45
- def valid_commit?(sha)
46
- return false if sha.nil? || sha.empty?
47
- return true if valid_ref?(sha)
39
+ def valid_commit?(ref)
40
+ return false if ref.nil? || ref.empty?
41
+ return true if valid_ref?(ref)
42
+ return false unless valid_url?
48
43
 
49
- # cloning is a last resort if for some reason we cannot
50
- # remotely get via ls-remote
51
44
  Dir.mktmpdir do |dir|
52
- run_command("#{CLONE_CMD} #{url} #{dir}", silent: true)
53
- Dir.chdir(dir) do
54
- _, status = run_command("#{SHOW_CMD} #{sha}", silent: true)
55
- status
56
- end
45
+ repo = Git.clone(url, dir, bare: true)
46
+ repo.rev_parse("#{ref}^{commit}")
47
+ true
57
48
  end
49
+ rescue Git::Error
50
+ false
58
51
  end
59
52
 
60
- # @return [Boolean] - return true if the ref is valid
61
- # @param url [String] - the git string either https or ssh url
62
- # @param ref [String] - the ref object, branch name, tag name, or commit sha, defaults to HEAD
53
+ # @param ref [String] branch name, tag name, HEAD, or a full/abbreviated SHA
54
+ # @return [Boolean]
63
55
  def valid_ref?(ref = 'HEAD')
64
- return false if ref.nil?
56
+ return false if ref.nil? || ref.empty?
65
57
 
66
- found = all_refs.find do |data|
67
- # we don't need to bother with these types
68
- next if %i[pull merge_request].include?(data[:type])
69
-
70
- # is the name equal to the tag or branch? Is the commit sha equal?
71
- data[:name].eql?(ref) || data[:sha].slice(0, 8).eql?(ref.slice(0, 8))
72
- end
73
- !found.nil?
74
- end
58
+ head = remote_refs.fetch('head', {})
59
+ return true if ref == 'HEAD' && !head.empty?
60
+ return true if sha_match?(head[:sha], ref)
75
61
 
76
- # @return [Array] - an array of all the refs associated with the remote repository
77
- # @param url [String] - the git string either https or ssh url
78
- # @example
79
- # [{:sha=>"0ec707e431367bbe2752966be8ab915b6f0da754", :ref=>"refs/heads/74110ac", :type=>:branch, :subtype=>nil, :name=>"74110ac"},
80
- # :sha=>"07bb5d2d94db222dca5860eb29c184e8970f36f4", :ref=>"refs/pull/74/head", :type=>:pull, :subtype=>:head, :name=>"74"},
81
- # :sha=>"156ca9a8ea69e056e86355b27d944e59d1b3a1e1", :ref=>"refs/heads/master", :type=>:branch, :subtype=>nil, :name=>"master"},
82
- # :sha=>"fcc0532bbc5a5b65f3941738339e9cc7e3d767ce", :ref=>"refs/pull/249/head", :type=>:pull, :subtype=>:head, :name=>"249"},
83
- # :sha=>"8d54891fa5df75890ee15d53080c2a81b4960f92", :ref=>"refs/pull/267/head", :type=>:pull, :subtype=>:head, :name=>"267"}]
84
- def all_refs
85
- @all_refs ||= remote_refs.each_with_object([]) do |line, refs|
86
- sha, ref = line.split("\t")
87
- next refs if line.include?('redirecting')
88
- next refs if sha.eql?('ref: refs/heads/master')
89
-
90
- _, type, name, subtype = ref.chomp.split('/')
91
- next refs unless name
92
-
93
- type = :tag if type.eql?('tags')
94
- type = type.to_sym
95
- subtype = subtype.to_sym if subtype
96
- type = :branch if type.eql?(:heads)
97
- refs << { sha: sha, ref: ref.chomp, type: type, subtype: subtype, name: name }
62
+ %w[branches tags].any? do |type|
63
+ refs = remote_refs.fetch(type, {})
64
+ refs.key?(ref) || refs.values.any? { |data| sha_match?(data[:sha], ref) }
98
65
  end
99
66
  end
100
67
 
101
- # @summary searches all the refs for a ref similar to the name provided
102
- # This is useful when looking for tags if a v or not a v
103
- # @param ref_name [String]
104
- # @return [String] the matching ref_name or nil
68
+ # @param ref_name [String] substring to find in a tag name
69
+ # @return [String, nil] matching tag name
105
70
  def get_ref_like(ref_name)
106
- return nil unless valid_url?
71
+ return nil if ref_name.nil? || ref_name.empty?
107
72
 
108
- all_refs.find do |ref|
109
- ref[:name].include?(ref_name)
73
+ remote_refs.fetch('tags', {}).each_key.find do |name|
74
+ !name.end_with?('^{}') && name.include?(ref_name)
110
75
  end
111
76
  end
112
77
 
113
- # useful for mocking easily
114
- # @param cmd [String]
115
- # @param silent [Boolean] set to true if you wish to send output to /dev/null, false by default
116
- # @return [Array]
117
- def self.run_command(cmd, silent: false)
118
- out_args = silent ? '2>&1 > /dev/null' : '2>&1'
119
- out = `#{cmd} #{out_args}`
120
- [out, $CHILD_STATUS.success?]
121
- end
78
+ private
79
+
80
+ def sha_match?(sha, ref)
81
+ return false unless sha
82
+
83
+ # \A and \z anchor the entire string; [0-9a-f] allows only hexadecimal digits.
84
+ # {8,64} accepts abbreviations of at least 8 digits up to a full SHA-256; i allows uppercase.
85
+ return false unless ref.match?(/\A[0-9a-f]{8,64}\z/i)
122
86
 
123
- def run_command(cmd, silent: false)
124
- self.class.run_command(cmd, silent: silent)
87
+ sha.start_with?(ref.downcase)
125
88
  end
126
89
  end
127
90
  end
@@ -1,3 +1,3 @@
1
1
  module Ra10ke
2
- VERSION = '4.5.1'
2
+ VERSION = '4.6.0'
3
3
  end
data/ra10ke.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.require_paths = ['lib']
17
17
  spec.required_ruby_version = '>= 3.1.0'
18
18
 
19
- spec.add_dependency 'git', '>= 1.18', '< 5.0'
19
+ spec.add_dependency 'git', '>= 2.0', '< 5.0'
20
20
  spec.add_dependency 'puppet_forge', '~> 6.0'
21
21
  spec.add_dependency 'r10k', '~> 5.0'
22
22
  spec.add_dependency 'rake', '~> 13.0', '>= 13.0.6'
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ra10ke'
5
+
6
+ RSpec.describe Ra10ke::Dependencies do
7
+ let(:url) { 'https://example.invalid/module.git' }
8
+ let(:metadata) do
9
+ PuppetForge::V3::Module.new(homepage_url: url, current_release: { metadata: { source: url } })
10
+ end
11
+ let(:forge_module) do
12
+ R10K::Module::Forge.new('example-module', fixtures_dir, version: '1.0.0')
13
+ end
14
+ let(:puppetfile) { instance_double(R10K::Puppetfile, load!: nil, forge: nil, modules: [forge_module]) }
15
+ let(:task_owner) { Ra10ke::RakeTask.new }
16
+
17
+ around do |example|
18
+ original_application = Rake.application
19
+ Rake.application = Rake::Application.new
20
+ example.run
21
+ ensure
22
+ Rake.application = original_application
23
+ end
24
+
25
+ before do
26
+ allow(forge_module).to receive_messages(v3_module: metadata, name: 'example-module')
27
+ allow(task_owner).to receive(:get_puppetfile).and_return(puppetfile)
28
+ end
29
+
30
+ it 'prints the matching tag name returned by GitRepo' do
31
+ allow(Git).to receive(:ls_remote).with(url).and_return(
32
+ 'tags' => { 'v1.0.0' => { ref: 'refs', sha: 'abc12345' } },
33
+ )
34
+ expected = <<~PUPPETFILE
35
+ mod 'example-module',
36
+ :git => '#{url}',
37
+ :ref => 'v1.0.0'
38
+
39
+ PUPPETFILE
40
+ expect { Rake::Task['r10k:print_git_conversion'].execute }.to output(expected).to_stdout
41
+ end
42
+
43
+ it 'prints the existing error message when no tag matches' do
44
+ allow(Git).to receive(:ls_remote).with(url).and_return({})
45
+ expected = <<~PUPPETFILE
46
+ mod 'example-module',
47
+ :git => '#{url}',
48
+ :ref => 'bad url or tag 1.0.0 is missing'
49
+
50
+ PUPPETFILE
51
+ expect { Rake::Task['r10k:print_git_conversion'].execute }.to output(expected).to_stdout
52
+ end
53
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
- require 'ra10ke/validate'
4
+ require 'ra10ke/git_repo'
5
5
 
6
6
  RSpec.describe 'Ra10ke::GitRepo' do
7
7
  let(:url) { 'https://github.com/vshn/puppet-gitlab' }
@@ -10,11 +10,12 @@ RSpec.describe 'Ra10ke::GitRepo' do
10
10
  expect(Ra10ke::GitRepo.new(url)).to be_a Ra10ke::GitRepo
11
11
  end
12
12
 
13
- it 'does not run_command more than once' do
13
+ it 'only fetches remote refs once' do
14
14
  i = Ra10ke::GitRepo.new(url)
15
- expect(i).to receive(:run_command).with("git ls-remote --symref #{url}").once
15
+ expect(Git).to receive(:ls_remote).with(url).once.and_return({})
16
16
  i.valid_url?
17
- i.all_refs
17
+ i.valid_ref?
18
+ i.get_ref_like('1.0.0')
18
19
  end
19
20
 
20
21
  describe 'good url' do
@@ -24,28 +25,56 @@ RSpec.describe 'Ra10ke::GitRepo' do
24
25
  Ra10ke::GitRepo.new(url)
25
26
  end
26
27
 
27
- let(:reflist) { File.read(File.join(fixtures_dir, 'refs', 'gitlab.txt')) }
28
+ let(:reflist) do
29
+ File.readlines(File.join(fixtures_dir, 'refs', 'gitlab.txt')).each_with_object({}) do |line, refs|
30
+ sha, ref = line.strip.split("\t")
31
+ if ref == 'HEAD'
32
+ refs['head'] = { ref: ref, sha: sha }
33
+ else
34
+ prefix, type, name = ref.split('/', 3)
35
+ type = 'branches' if type == 'heads'
36
+ refs[type] ||= {}
37
+ refs[type][name] = { ref: prefix, sha: sha }
38
+ end
39
+ end
40
+ end
28
41
 
29
42
  before do
30
- allow(instance).to receive(:run_command).with("git ls-remote --symref #{url}").and_return([reflist, true])
43
+ allow(Git).to receive(:ls_remote).with(url).and_return(reflist)
31
44
  end
32
45
 
33
- it '#remote_refs is array' do
34
- expect(instance.remote_refs).to be_a Array
46
+ it '#remote_refs returns the gem hash unchanged' do
47
+ expect(instance.remote_refs).to equal(reflist)
35
48
  end
36
49
 
37
50
  it '#remote_refs contains refs' do
38
- expect(instance.remote_refs.first).to eq("1b3322d525e96bf7d0565b08703e2a44c90e7b4a\tHEAD\n")
51
+ expect(instance.remote_refs['head']).to eq(ref: 'HEAD', sha: '1b3322d525e96bf7d0565b08703e2a44c90e7b4a')
39
52
  end
40
53
 
41
54
  it '#get_ref_like' do
42
- expect(instance.get_ref_like('8.0.0'))
55
+ expect(instance.get_ref_like('5.0.0')).to eq('v5.0.0')
43
56
  end
44
57
 
45
58
  it '#valid_ref?' do
46
59
  expect(instance.valid_ref?('master')).to be true
47
60
  end
48
61
 
62
+ it 'accepts HEAD explicitly and as the default ref' do
63
+ expect(instance.valid_ref?('HEAD')).to be true
64
+ expect(instance.valid_ref?).to be true
65
+ end
66
+
67
+ it 'excludes pull and merge request refs from validation' do
68
+ allow(Git).to receive(:ls_remote).with(url).and_return(
69
+ 'pull' => { '74/head' => { ref: 'refs', sha: 'abc12345' } },
70
+ 'merge_request' => { '12/merge' => { ref: 'refs', sha: 'def12345' } },
71
+ )
72
+ expect(instance.valid_ref?('74')).to be false
73
+ expect(instance.valid_ref?('abc12345')).to be false
74
+ expect(instance.valid_ref?('12')).to be false
75
+ expect(instance.valid_ref?('def12345')).to be false
76
+ end
77
+
49
78
  it '#valid_commit?' do
50
79
  expect(instance.valid_commit?('master')).to be true
51
80
  end
@@ -55,8 +84,9 @@ RSpec.describe 'Ra10ke::GitRepo' do
55
84
  end
56
85
 
57
86
  it '#valid_commit? but invalid sha' do
58
- allow(instance).to receive(:run_command).with(/clone/, silent: true).and_return([nil, true])
59
- allow(instance).to receive(:run_command).with(/git\sshow.*/, silent: true).and_return([nil, false])
87
+ repo = instance_double(Git::Base)
88
+ allow(Git).to receive(:clone).with(url, kind_of(String), bare: true).and_return(repo)
89
+ allow(repo).to receive(:rev_parse).with('invalid^{commit}').and_raise(Git::Error)
60
90
  expect(instance.valid_commit?('invalid')).to be false
61
91
  end
62
92
 
@@ -64,13 +94,28 @@ RSpec.describe 'Ra10ke::GitRepo' do
64
94
  expect(instance.valid_url?).to be true
65
95
  end
66
96
 
67
- it '#all_refs is a Array of Hashes' do
68
- refs = instance.all_refs
69
- expect(refs).to be_a Array
70
- expect(refs.last).to eq(
71
- { name: 'v5.0.0^{}', ref: 'refs/tags/v5.0.0^{}', sha: '1febd15f90d32e6b3d6c242a70db386b2ef1942c', subtype: nil,
72
- type: :tag, },
97
+ it 'accepts full and abbreviated SHAs but checks all supplied characters' do
98
+ sha = reflist['head'][:sha]
99
+ expect(instance.valid_ref?(sha)).to be true
100
+ expect(instance.valid_ref?(sha[0, 8])).to be true
101
+ expect(instance.valid_ref?(sha[0, 12])).to be true
102
+ expect(instance.valid_ref?("#{sha[0, 8]}#{'0' * 32}")).to be false
103
+ expect(instance.valid_ref?("#{sha}0")).to be false
104
+ expect(instance.valid_ref?(sha[0, 7])).to be false
105
+ end
106
+
107
+ it 'validates the peeled commit SHA of an annotated tag' do
108
+ expect(instance.valid_ref?('1febd15f90d32e6b3d6c242a70db386b2ef1942c')).to be true
109
+ end
110
+
111
+ it 'searches only tag names and skips peeled tag entries' do
112
+ allow(Git).to receive(:ls_remote).with(url).and_return(
113
+ 'branches' => { 'feature/5.0.0' => { ref: 'refs', sha: 'abc12345' } },
114
+ 'tags' => { 'v5.0.0^{}' => { ref: 'refs', sha: 'abc12345' }, 'v5.0.0' => { ref: 'refs', sha: 'def12345' } },
73
115
  )
116
+ expect(instance.get_ref_like('5.0.0')).to eq('v5.0.0')
117
+ expect(instance.get_ref_like('feature')).to be_nil
118
+ expect(instance.get_ref_like('^{}')).to be_nil
74
119
  end
75
120
  end
76
121
 
@@ -81,12 +126,143 @@ RSpec.describe 'Ra10ke::GitRepo' do
81
126
  end
82
127
 
83
128
  before do
84
- allow(instance).to receive(:run_command).with("git ls-remote --symref #{url}").and_return(['', false])
129
+ allow(Git).to receive(:ls_remote).with(url).and_raise(Git::Error)
130
+ end
131
+
132
+ it 'returns empty remote refs and rejects HEAD' do
133
+ expect(instance.remote_refs).to eq({})
134
+ expect(instance.valid_ref?).to be false
135
+ end
136
+ end
137
+
138
+ describe 'failed remote lookup' do
139
+ it 'caches the failure and reports an invalid URL' do
140
+ repo = Ra10ke::GitRepo.new(url)
141
+ expect(Git).to receive(:ls_remote).with(url).once.and_raise(Git::Error)
142
+ expect(repo.valid_url?).to be false
143
+ expect(repo.remote_refs).to eq({})
144
+ expect(repo.get_ref_like('missing')).to be_nil
145
+ expect(Git).not_to receive(:clone)
146
+ expect(repo.valid_commit?('missing')).to be false
147
+ end
148
+ end
149
+
150
+ describe '#valid_commit?' do
151
+ let(:instance) { Ra10ke::GitRepo.new(url) }
152
+
153
+ before do
154
+ allow(Git).to receive(:ls_remote).with(url).and_return('head' => { ref: 'HEAD', sha: 'a' * 40 })
155
+ end
156
+
157
+ it 'does not clone for an empty SHA' do
158
+ expect(Git).not_to receive(:clone)
159
+ expect(instance.valid_commit?('')).to be false
160
+ end
161
+
162
+ it 'stops after a failed clone and removes the temporary directory' do
163
+ clone_dir = nil
164
+ expect(Git).to receive(:clone).with(url, kind_of(String), bare: true) do |_, dir|
165
+ clone_dir = dir
166
+ raise Git::Error
167
+ end
168
+ expect(instance.valid_commit?('missing')).to be false
169
+ expect(File.exist?(clone_dir)).to be false
170
+ end
171
+ end
172
+
173
+ describe '.current_branch' do
174
+ it 'handles nil returned by older git gem versions for detached HEAD' do
175
+ repo = instance_double(Git::Base, current_branch: nil)
176
+ allow(Git).to receive(:open).with('repo').and_return(repo)
177
+ expect(Ra10ke::GitRepo.current_branch('repo')).to be_nil
178
+ end
179
+
180
+ it 'returns nil for a directory without a repository' do
181
+ Dir.mktmpdir do |dir|
182
+ expect(Ra10ke::GitRepo.current_branch(dir)).to be_nil
183
+ end
184
+ end
185
+
186
+ it 'returns nil for a missing directory' do
187
+ Dir.mktmpdir do |dir|
188
+ expect(Ra10ke::GitRepo.current_branch(File.join(dir, 'missing'))).to be_nil
189
+ end
190
+ end
191
+ end
192
+
193
+ describe 'with a local repository' do
194
+ let(:tmpdir) { Dir.mktmpdir('ra10ke git repo ') }
195
+ let(:path) { File.join(tmpdir, 'source repo') }
196
+ let(:local_repo) { Git.init(path) }
197
+ let(:older_sha) { local_repo.revparse('HEAD~1') }
198
+
199
+ around do |example|
200
+ example.run
201
+ ensure
202
+ FileUtils.remove_entry(tmpdir)
203
+ end
204
+
205
+ before do
206
+ local_repo.config('user.name', 'Ra10ke Test')
207
+ local_repo.config('user.email', 'ra10ke@example.invalid')
208
+ local_repo.config('commit.gpgsign', 'false')
209
+ local_repo.config('tag.gpgsign', 'false')
210
+ File.write(File.join(path, 'file'), 'first')
211
+ local_repo.add('file')
212
+ local_repo.commit('first')
213
+ File.write(File.join(path, 'file'), 'second')
214
+ local_repo.add('file')
215
+ local_repo.commit('second')
216
+ local_repo.add_tag('v1.0.0')
217
+ local_repo.add_tag('v2.0.0', annotate: true, message: 'annotated tag')
218
+ end
219
+
220
+ it 'returns the branch without changing the working directory' do
221
+ cwd = Dir.pwd
222
+ expect(Ra10ke::GitRepo.current_branch(path)).to eq(local_repo.current_branch)
223
+ expect(Dir.pwd).to eq(cwd)
224
+ end
225
+
226
+ it 'returns nil for detached HEAD' do
227
+ local_repo.checkout(older_sha)
228
+ expect(Ra10ke::GitRepo.current_branch(path)).to be_nil
229
+ end
230
+
231
+ it 'finds branches, lightweight tags and annotated tags' do
232
+ repo = Ra10ke::GitRepo.new(path)
233
+ expect(repo.valid_url?).to be true
234
+ expect(repo.valid_ref?(local_repo.current_branch)).to be true
235
+ expect(repo.valid_ref?('v1.0.0')).to be true
236
+ expect(repo.valid_ref?('v2.0.0')).to be true
237
+ expect(repo.get_ref_like('2.0.0')).to eq('v2.0.0')
238
+ end
239
+
240
+ it 'preserves branch and tag names containing slashes' do
241
+ local_repo.branch('feature/example').create
242
+ local_repo.add_tag('release/v1.0.0')
243
+ repo = Ra10ke::GitRepo.new(path)
244
+ expect(repo.valid_ref?('feature/example')).to be true
245
+ expect(repo.valid_ref?('release/v1.0.0')).to be true
246
+ expect(repo.get_ref_like('release/')).to eq('release/v1.0.0')
247
+ end
248
+
249
+ it 'recognizes remote HEAD from the gem lookup' do
250
+ repo = Ra10ke::GitRepo.new(path)
251
+ expect(repo.valid_ref?).to be true
252
+ expect(repo.valid_ref?(local_repo.revparse('HEAD'))).to be true
253
+ end
254
+
255
+ it 'rejects a blob object during the commit fallback check' do
256
+ repo = Ra10ke::GitRepo.new(path)
257
+ blob_sha = local_repo.rev_parse('HEAD:file')
258
+ expect(repo.valid_commit?(blob_sha)).to be false
85
259
  end
86
260
 
87
- it '#all_refs' do
88
- expect(instance.all_refs).to be_a Array
89
- expect(instance.all_refs).to eq []
261
+ it 'clones to validate a commit that is not advertised by a ref' do
262
+ repo = Ra10ke::GitRepo.new(path)
263
+ expect(repo.valid_ref?(older_sha)).to be false
264
+ expect(repo.valid_commit?(older_sha)).to be true
265
+ expect(repo.valid_commit?('invalid')).to be false
90
266
  end
91
267
  end
92
268
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ra10ke
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.5.1
4
+ version: 4.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Theo Chatzimichos
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.18'
19
+ version: '2.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '5.0'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '1.18'
29
+ version: '2.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '5.0'
@@ -168,7 +168,9 @@ extensions: []
168
168
  extra_rdoc_files: []
169
169
  files:
170
170
  - ".github/dependabot.yml"
171
+ - ".github/labeler.yml"
171
172
  - ".github/release.yml"
173
+ - ".github/workflows/labeler.yml"
172
174
  - ".github/workflows/release.yml"
173
175
  - ".github/workflows/test.yml"
174
176
  - ".gitignore"
@@ -207,6 +209,7 @@ files:
207
209
  - spec/fixtures/refs/gitlab.txt
208
210
  - spec/fixtures/refs/r10k.txt
209
211
  - spec/fixtures/refs/reflist.txt
212
+ - spec/ra10ke/dependencies_git_conversion_spec.rb
210
213
  - spec/ra10ke/dependencies_spec.rb
211
214
  - spec/ra10ke/deprecation_spec.rb
212
215
  - spec/ra10ke/diff_spec.rb
@@ -235,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
238
  - !ruby/object:Gem::Version
236
239
  version: '0'
237
240
  requirements: []
238
- rubygems_version: 4.0.6
241
+ rubygems_version: 4.0.20
239
242
  specification_version: 4
240
243
  summary: Syntax check for the Puppetfile, check for outdated installed puppet modules
241
244
  test_files: []