ra10ke 4.5.0 → 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 +4 -4
- data/.github/labeler.yml +5 -0
- data/.github/workflows/labeler.yml +17 -0
- data/.github/workflows/release.yml +7 -7
- data/.github/workflows/test.yml +3 -3
- data/CHANGELOG.md +20 -0
- data/Gemfile +1 -1
- data/lib/ra10ke/dependencies.rb +1 -2
- data/lib/ra10ke/git_repo.rb +43 -80
- data/lib/ra10ke/solve.rb +43 -26
- data/lib/ra10ke/version.rb +1 -1
- data/ra10ke.gemspec +1 -1
- data/spec/ra10ke/dependencies_git_conversion_spec.rb +53 -0
- data/spec/ra10ke/git_repo_spec.rb +198 -22
- data/spec/ra10ke/solve_spec.rb +174 -0
- metadata +8 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a77b7170e6dfb723d530dc22553a16ca198a0b361ca3a2aac5169b05fb0e4c89
|
|
4
|
+
data.tar.gz: b8025d8e38a8051a8a3cf4baa8b214e74b96c8ea5230364a37b23ac22f210a61
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0047a09a069462ef4d25e9778b83558aa29e9c282106e1f32eafd1fcc87df65d25e31fb9becccfa4d4ae47e4b61d930dafc15fcd56cd56b4669801675c3c415f
|
|
7
|
+
data.tar.gz: 4d809b1fa050a40ab3e1a265999eb47c1eb337609586b06c87b7fa3537303e42721a6d8ad8c84bd3264d2b0a183e3f2a91334054520730b39bde47193fc346de
|
data/.github/labeler.yml
ADDED
|
@@ -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@
|
|
18
|
+
- uses: actions/checkout@v7
|
|
19
19
|
- name: Install Ruby
|
|
20
20
|
uses: ruby/setup-ruby@v1
|
|
21
21
|
with:
|
|
@@ -24,7 +24,7 @@ jobs:
|
|
|
24
24
|
shell: bash
|
|
25
25
|
run: gem build --verbose *.gemspec
|
|
26
26
|
- name: Upload gem to GitHub cache
|
|
27
|
-
uses: actions/upload-artifact@
|
|
27
|
+
uses: actions/upload-artifact@v7
|
|
28
28
|
with:
|
|
29
29
|
name: gem-artifact
|
|
30
30
|
path: '*.gem'
|
|
@@ -39,7 +39,7 @@ jobs:
|
|
|
39
39
|
contents: write # clone repo and create release
|
|
40
40
|
steps:
|
|
41
41
|
- name: Download gem from GitHub cache
|
|
42
|
-
uses: actions/download-artifact@
|
|
42
|
+
uses: actions/download-artifact@v8
|
|
43
43
|
with:
|
|
44
44
|
name: gem-artifact
|
|
45
45
|
- name: Create Release
|
|
@@ -56,7 +56,7 @@ jobs:
|
|
|
56
56
|
packages: write # publish to rubygems.pkg.github.com
|
|
57
57
|
steps:
|
|
58
58
|
- name: Download gem from GitHub cache
|
|
59
|
-
uses: actions/download-artifact@
|
|
59
|
+
uses: actions/download-artifact@v8
|
|
60
60
|
with:
|
|
61
61
|
name: gem-artifact
|
|
62
62
|
- name: Publish gem to GitHub packages
|
|
@@ -73,10 +73,10 @@ jobs:
|
|
|
73
73
|
id-token: write # rubygems.org authentication
|
|
74
74
|
steps:
|
|
75
75
|
- name: Download gem from GitHub cache
|
|
76
|
-
uses: actions/download-artifact@
|
|
76
|
+
uses: actions/download-artifact@v8
|
|
77
77
|
with:
|
|
78
78
|
name: gem-artifact
|
|
79
|
-
- uses: rubygems/configure-rubygems-credentials@
|
|
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
|
|
@@ -92,7 +92,7 @@ jobs:
|
|
|
92
92
|
- release-to-rubygems
|
|
93
93
|
steps:
|
|
94
94
|
- name: Download gem from GitHub cache
|
|
95
|
-
uses: actions/download-artifact@
|
|
95
|
+
uses: actions/download-artifact@v8
|
|
96
96
|
with:
|
|
97
97
|
name: gem-artifact
|
|
98
98
|
- name: Install Ruby
|
data/.github/workflows/test.yml
CHANGED
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
outputs:
|
|
17
17
|
ruby: ${{ steps.ruby.outputs.versions }}
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
20
|
- name: Install Ruby ${{ matrix.ruby }}
|
|
21
21
|
uses: ruby/setup-ruby@v1
|
|
22
22
|
with:
|
|
@@ -25,7 +25,7 @@ jobs:
|
|
|
25
25
|
- name: Run Rubocop
|
|
26
26
|
run: bundle exec rake rubocop
|
|
27
27
|
- id: ruby
|
|
28
|
-
uses: voxpupuli/ruby-version@
|
|
28
|
+
uses: voxpupuli/ruby-version@v2
|
|
29
29
|
test:
|
|
30
30
|
runs-on: ubuntu-latest
|
|
31
31
|
needs: rubocop_and_matrix
|
|
@@ -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@
|
|
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,26 @@
|
|
|
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
|
+
|
|
13
|
+
## [v4.5.1](https://github.com/voxpupuli/ra10ke/tree/v4.5.1) (2026-05-11)
|
|
14
|
+
|
|
15
|
+
[Full Changelog](https://github.com/voxpupuli/ra10ke/compare/v4.5.0...v4.5.1)
|
|
16
|
+
|
|
17
|
+
**Fixed bugs:**
|
|
18
|
+
|
|
19
|
+
- fix: process git modules before Forge modules to prevent dependency conflicts [\#145](https://github.com/voxpupuli/ra10ke/pull/145) ([bastelfreak](https://github.com/bastelfreak))
|
|
20
|
+
|
|
21
|
+
**Closed issues:**
|
|
22
|
+
|
|
23
|
+
- r10k:solve\_dependencies pulls in outdated constraints from last forge release as implicit dependency instead of explicit git module [\#128](https://github.com/voxpupuli/ra10ke/issues/128)
|
|
24
|
+
|
|
5
25
|
## [v4.5.0](https://github.com/voxpupuli/ra10ke/tree/v4.5.0) (2025-10-16)
|
|
6
26
|
|
|
7
27
|
[Full Changelog](https://github.com/voxpupuli/ra10ke/compare/v4.4.0...v4.5.0)
|
data/Gemfile
CHANGED
data/lib/ra10ke/dependencies.rb
CHANGED
|
@@ -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
|
-
|
|
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}',
|
data/lib/ra10ke/git_repo.rb
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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 [
|
|
29
|
-
# return empty
|
|
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
|
-
|
|
33
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
# @
|
|
61
|
-
# @
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
# @
|
|
102
|
-
#
|
|
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
|
|
71
|
+
return nil if ref_name.nil? || ref_name.empty?
|
|
107
72
|
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
124
|
-
self.class.run_command(cmd, silent: silent)
|
|
87
|
+
sha.start_with?(ref.downcase)
|
|
125
88
|
end
|
|
126
89
|
end
|
|
127
90
|
end
|
data/lib/ra10ke/solve.rb
CHANGED
|
@@ -50,38 +50,26 @@ module Ra10ke::Solve
|
|
|
50
50
|
# List of modules we have in the Puppetfile, as [name, version] pairs
|
|
51
51
|
@current_modules = []
|
|
52
52
|
|
|
53
|
+
# Single pass: partition modules into git/Forge arrays and simultaneously seed
|
|
54
|
+
# @processed_modules with all git module names. Seeding upfront prevents
|
|
55
|
+
# add_reqs_to_graph from fetching Forge releases for any git module encountered
|
|
56
|
+
# as a transitive dependency, regardless of declaration order in the Puppetfile.
|
|
57
|
+
git_modules = []
|
|
58
|
+
forge_modules = []
|
|
53
59
|
puppetfile.modules.each do |puppet_module|
|
|
54
60
|
next if ignore_modules.include? puppet_module.title
|
|
55
61
|
|
|
56
62
|
if puppet_module.instance_of?(R10K::Module::Forge)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
@graph.artifact(module_name, installed_version)
|
|
62
|
-
constraint = '>=0.0.0'
|
|
63
|
-
unless allow_major_bump
|
|
64
|
-
ver = Semverse::Version.new installed_version
|
|
65
|
-
if ver.major.zero?
|
|
66
|
-
constraint = "~>#{installed_version}"
|
|
67
|
-
else
|
|
68
|
-
nver = Semverse::Version.new([ver.major + 1, 0, 0])
|
|
69
|
-
constraint = "<#{nver}"
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
puts "...Adding a demand: #{module_name} #{constraint}"
|
|
73
|
-
|
|
74
|
-
@demands.add([module_name, constraint])
|
|
75
|
-
puts '...Fetching latest release version information'
|
|
76
|
-
forge_rel = PuppetForge::Module.find(module_name).current_release
|
|
77
|
-
mod = @graph.artifact(module_name, forge_rel.version)
|
|
78
|
-
puts '...Adding its requirements to the graph'
|
|
79
|
-
meta = get_release_metadata(module_name, forge_rel)
|
|
80
|
-
add_reqs_to_graph(mod, meta)
|
|
63
|
+
forge_modules << puppet_module
|
|
64
|
+
elsif puppet_module.instance_of?(R10K::Module::Git)
|
|
65
|
+
@processed_modules.add(puppet_module.title.tr('/', '-'))
|
|
66
|
+
git_modules << puppet_module
|
|
81
67
|
end
|
|
68
|
+
end
|
|
82
69
|
|
|
83
|
-
|
|
84
|
-
|
|
70
|
+
# Process git modules first so their metadata populates the graph before
|
|
71
|
+
# any Forge module's transitive dependencies are resolved.
|
|
72
|
+
git_modules.each do |puppet_module|
|
|
85
73
|
# This downloads the git module to modules/modulename
|
|
86
74
|
meta = fetch_git_metadata(puppet_module)
|
|
87
75
|
version = get_key_or_sym(meta, :version)
|
|
@@ -95,6 +83,35 @@ module Ra10ke::Solve
|
|
|
95
83
|
puts "...Adding requirements for git module #{module_name}-#{version}"
|
|
96
84
|
add_reqs_to_graph(mod, meta)
|
|
97
85
|
end
|
|
86
|
+
|
|
87
|
+
# Process Forge modules. Any git module already in @processed_modules will
|
|
88
|
+
# be skipped by add_reqs_to_graph when encountered as a transitive dependency.
|
|
89
|
+
forge_modules.each do |puppet_module|
|
|
90
|
+
module_name = puppet_module.title.tr('/', '-')
|
|
91
|
+
installed_version = puppet_module.expected_version
|
|
92
|
+
puts "Processing Forge module #{module_name}-#{installed_version}"
|
|
93
|
+
@current_modules << [module_name, installed_version]
|
|
94
|
+
@graph.artifact(module_name, installed_version)
|
|
95
|
+
constraint = '>=0.0.0'
|
|
96
|
+
unless allow_major_bump
|
|
97
|
+
ver = Semverse::Version.new installed_version
|
|
98
|
+
if ver.major.zero?
|
|
99
|
+
constraint = "~>#{installed_version}"
|
|
100
|
+
else
|
|
101
|
+
nver = Semverse::Version.new([ver.major + 1, 0, 0])
|
|
102
|
+
constraint = "<#{nver}"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
puts "...Adding a demand: #{module_name} #{constraint}"
|
|
106
|
+
|
|
107
|
+
@demands.add([module_name, constraint])
|
|
108
|
+
puts '...Fetching latest release version information'
|
|
109
|
+
forge_rel = PuppetForge::Module.find(module_name).current_release
|
|
110
|
+
mod = @graph.artifact(module_name, forge_rel.version)
|
|
111
|
+
puts '...Adding its requirements to the graph'
|
|
112
|
+
meta = get_release_metadata(module_name, forge_rel)
|
|
113
|
+
add_reqs_to_graph(mod, meta)
|
|
114
|
+
end
|
|
98
115
|
puts
|
|
99
116
|
puts 'Resolving dependencies...'
|
|
100
117
|
puts 'WARNING: Potentially breaking updates are allowed for this resolution' if allow_major_bump
|
data/lib/ra10ke/version.rb
CHANGED
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', '>=
|
|
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/
|
|
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 '
|
|
13
|
+
it 'only fetches remote refs once' do
|
|
14
14
|
i = Ra10ke::GitRepo.new(url)
|
|
15
|
-
expect(
|
|
15
|
+
expect(Git).to receive(:ls_remote).with(url).once.and_return({})
|
|
16
16
|
i.valid_url?
|
|
17
|
-
i.
|
|
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)
|
|
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(
|
|
43
|
+
allow(Git).to receive(:ls_remote).with(url).and_return(reflist)
|
|
31
44
|
end
|
|
32
45
|
|
|
33
|
-
it '#remote_refs
|
|
34
|
-
expect(instance.remote_refs).to
|
|
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
|
|
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('
|
|
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
|
-
|
|
59
|
-
allow(
|
|
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 '
|
|
68
|
-
|
|
69
|
-
expect(
|
|
70
|
-
expect(
|
|
71
|
-
|
|
72
|
-
|
|
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(
|
|
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 '
|
|
88
|
-
|
|
89
|
-
expect(
|
|
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
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec::Mocks.configuration.allow_message_expectations_on_nil = true
|
|
6
|
+
|
|
7
|
+
RSpec.describe Ra10ke::Solve do
|
|
8
|
+
# Minimal helper class that mixes in the module so we can test its private methods.
|
|
9
|
+
let(:instance) do
|
|
10
|
+
klass = Class.new do
|
|
11
|
+
include Ra10ke::Solve
|
|
12
|
+
|
|
13
|
+
# Expose private helpers for direct testing.
|
|
14
|
+
public :get_key_or_sym, :get_version_req, :print_module_diff, :add_reqs_to_graph
|
|
15
|
+
|
|
16
|
+
def initialize
|
|
17
|
+
@graph = Solve::Graph.new
|
|
18
|
+
@processed_modules = Set.new
|
|
19
|
+
@demands = Set.new
|
|
20
|
+
# @metadata_cache is intentionally left nil here; tests that need it
|
|
21
|
+
# set it via instance_variable_set in a before block.
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
klass.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
let(:processed_modules) { instance.instance_variable_get(:@processed_modules) }
|
|
28
|
+
let(:demands) { instance.instance_variable_get(:@demands) }
|
|
29
|
+
let(:graph) { instance.instance_variable_get(:@graph) }
|
|
30
|
+
|
|
31
|
+
# -------------------------------------------------------------------------
|
|
32
|
+
describe '#get_key_or_sym' do
|
|
33
|
+
it 'fetches a value by symbol key' do
|
|
34
|
+
expect(instance.get_key_or_sym({ version: '1.0.0' }, :version)).to eq('1.0.0')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'fetches a value by string key when only the string form is present' do
|
|
38
|
+
expect(instance.get_key_or_sym({ 'version' => '2.0.0' }, :version)).to eq('2.0.0')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'prefers the symbol key over the string key when both are present' do
|
|
42
|
+
expect(instance.get_key_or_sym({ version: 'sym', 'version' => 'str' }, :version)).to eq('sym')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'returns nil when the key is absent in both forms' do
|
|
46
|
+
expect(instance.get_key_or_sym({}, :version)).to be_nil
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# -------------------------------------------------------------------------
|
|
51
|
+
describe '#get_version_req' do
|
|
52
|
+
it 'returns version_requirement when present' do
|
|
53
|
+
expect(instance.get_version_req({ version_requirement: '>= 1.0.0' })).to eq('>= 1.0.0')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'falls back to version_range when version_requirement is absent' do
|
|
57
|
+
expect(instance.get_version_req({ version_range: '>= 2.0.0' })).to eq('>= 2.0.0')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'returns nil when neither key is present' do
|
|
61
|
+
expect(instance.get_version_req({})).to be_nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'works with string keys' do
|
|
65
|
+
expect(instance.get_version_req({ 'version_requirement' => '~> 3.0' })).to eq('~> 3.0')
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# -------------------------------------------------------------------------
|
|
70
|
+
describe '#print_module_diff' do
|
|
71
|
+
it 'reports OUTDATED for a module whose version has changed' do
|
|
72
|
+
expect do
|
|
73
|
+
instance.print_module_diff([['foo-bar', '1.0.0']], [['foo-bar', '2.0.0']])
|
|
74
|
+
end.to output(/OUTDATED.*foo-bar.*1\.0\.0.*2\.0\.0/).to_stdout
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'reports MISSING for a module present in the resolution but not in current' do
|
|
78
|
+
expect do
|
|
79
|
+
instance.print_module_diff([], [['missing-mod', '1.2.3']])
|
|
80
|
+
end.to output(/MISSING.*missing-mod.*1\.2\.3/).to_stdout
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'produces no output when all modules are up to date' do
|
|
84
|
+
expect do
|
|
85
|
+
instance.print_module_diff([['foo-bar', '1.0.0']], [['foo-bar', '1.0.0']])
|
|
86
|
+
end.not_to output.to_stdout
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'reports all outdated modules in a single pass' do
|
|
90
|
+
current = [['aaa-one', '1.0.0'], ['bbb-two', '2.0.0']]
|
|
91
|
+
resolution = [['aaa-one', '1.1.0'], ['bbb-two', '2.1.0']]
|
|
92
|
+
expect do
|
|
93
|
+
instance.print_module_diff(current, resolution)
|
|
94
|
+
end.to output(/aaa-one.*bbb-two/m).to_stdout
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# -------------------------------------------------------------------------
|
|
99
|
+
describe '#add_reqs_to_graph' do
|
|
100
|
+
let(:artifact) { graph.artifact('mymod', '1.0.0') }
|
|
101
|
+
|
|
102
|
+
context 'when the dependency is already in @processed_modules' do
|
|
103
|
+
before { processed_modules.add('puppetlabs-stdlib') }
|
|
104
|
+
|
|
105
|
+
it 'does not attempt a Forge lookup' do
|
|
106
|
+
meta = { name: 'mymod', dependencies: [{ name: 'puppetlabs/stdlib', version_requirement: '>= 4.0.0' }] }
|
|
107
|
+
expect(PuppetForge::Module).not_to receive(:find)
|
|
108
|
+
instance.add_reqs_to_graph(artifact, meta)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'adds the dependency name to @demands' do
|
|
112
|
+
meta = { name: 'mymod', dependencies: [{ name: 'puppetlabs/stdlib', version_requirement: '>= 4.0.0' }] }
|
|
113
|
+
instance.add_reqs_to_graph(artifact, meta)
|
|
114
|
+
expect(demands).to include('puppetlabs-stdlib')
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'records the version constraint on the artifact' do
|
|
118
|
+
meta = { name: 'mymod', dependencies: [{ name: 'puppetlabs/stdlib', version_requirement: '>= 4.0.0' }] }
|
|
119
|
+
instance.add_reqs_to_graph(artifact, meta)
|
|
120
|
+
dep = artifact.dependencies.find { |d| d.name == 'puppetlabs-stdlib' }
|
|
121
|
+
expect(dep).not_to be_nil
|
|
122
|
+
expect(dep.constraint.to_s).to eq('>= 4.0.0')
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
context 'when no_demands flag is set' do
|
|
127
|
+
before { processed_modules.add('puppetlabs-stdlib') }
|
|
128
|
+
|
|
129
|
+
it 'does not add the dependency to @demands' do
|
|
130
|
+
meta = { name: 'mymod', dependencies: [{ name: 'puppetlabs/stdlib', version_requirement: '>= 4.0.0' }] }
|
|
131
|
+
instance.add_reqs_to_graph(artifact, meta, :no_demands)
|
|
132
|
+
expect(demands).not_to include('puppetlabs-stdlib')
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context 'when dependency has an invalid version constraint' do
|
|
137
|
+
before { processed_modules.add('puppetlabs-badmod') }
|
|
138
|
+
|
|
139
|
+
it 'prints a warning and continues without raising' do
|
|
140
|
+
meta = { name: 'mymod', dependencies: [{ name: 'puppetlabs/badmod', version_requirement: 'not_valid' }] }
|
|
141
|
+
expect do
|
|
142
|
+
instance.add_reqs_to_graph(artifact, meta)
|
|
143
|
+
end.to output(/WARNING.*Invalid version constraint/).to_stdout
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
context 'when dependency has no version constraint' do
|
|
148
|
+
before { processed_modules.add('puppetlabs-nover') }
|
|
149
|
+
|
|
150
|
+
it 'falls back to >=0.0.0 and does not raise' do
|
|
151
|
+
meta = { name: 'mymod', dependencies: [{ name: 'puppetlabs/nover' }] }
|
|
152
|
+
expect { instance.add_reqs_to_graph(artifact, meta) }.not_to raise_error
|
|
153
|
+
dep = artifact.dependencies.find { |d| d.name == 'puppetlabs-nover' }
|
|
154
|
+
expect(dep.constraint.to_s).to eq('>= 0.0.0')
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
context 'when dependency has a compound constraint (>=x <y)' do
|
|
159
|
+
before { processed_modules.add('puppetlabs-compound') }
|
|
160
|
+
|
|
161
|
+
it 'records both bounds on the artifact' do
|
|
162
|
+
meta = {
|
|
163
|
+
name: 'mymod',
|
|
164
|
+
dependencies: [{ name: 'puppetlabs/compound', version_requirement: '>= 4.0.0 <9.0.0' }],
|
|
165
|
+
}
|
|
166
|
+
instance.add_reqs_to_graph(artifact, meta)
|
|
167
|
+
constraints = artifact.dependencies.select { |d| d.name == 'puppetlabs-compound' }
|
|
168
|
+
.map { |d| d.constraint.to_s }
|
|
169
|
+
expect(constraints).to include('>= 4.0.0')
|
|
170
|
+
expect(constraints).to include('< 9.0.0')
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
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.
|
|
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: '
|
|
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: '
|
|
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,12 +209,14 @@ 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
|
|
213
216
|
- spec/ra10ke/duplicates_spec.rb
|
|
214
217
|
- spec/ra10ke/git_repo_spec.rb
|
|
215
218
|
- spec/ra10ke/puppetfile_parser_spec.rb
|
|
219
|
+
- spec/ra10ke/solve_spec.rb
|
|
216
220
|
- spec/ra10ke/validate_spec.rb
|
|
217
221
|
- spec/ra10ke_spec.rb
|
|
218
222
|
- spec/spec_helper.rb
|
|
@@ -234,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
234
238
|
- !ruby/object:Gem::Version
|
|
235
239
|
version: '0'
|
|
236
240
|
requirements: []
|
|
237
|
-
rubygems_version:
|
|
241
|
+
rubygems_version: 4.0.20
|
|
238
242
|
specification_version: 4
|
|
239
243
|
summary: Syntax check for the Puppetfile, check for outdated installed puppet modules
|
|
240
244
|
test_files: []
|