ra10ke 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +12 -0
- data/lib/ra10ke/solve.rb +227 -0
- data/lib/ra10ke/version.rb +1 -1
- data/lib/ra10ke.rb +7 -4
- data/ra10ke.gemspec +1 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4483e49e41d8b69e98d4730662b79084a670580b
|
4
|
+
data.tar.gz: 0bf2f4d16f66755a60f3653852900e46983136f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de78be1d8e3146d55b207bd48f100f00cd36e310f857d3de3d2cb831dc894c63b3196fa1aa75dd8fda9964c46e1f6f0412507ebb22863a2ec8e19a37bf39fb2c
|
7
|
+
data.tar.gz: 36087c043bb91a4a4b034fb86fc5695c6d2ea74c4ed5ababcb3737b2477ee9714fe30afb8544741feb73a306deacc41633341a7acbf41a354203480776ca223e
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
=========
|
3
3
|
|
4
|
+
0.3.0
|
5
|
+
-----
|
6
|
+
|
7
|
+
2017-10-08
|
8
|
+
|
9
|
+
* [#6](https://github.com/voxpupuli/ra10ke/pull/6) Add a dependency solver based on the Ruby Solve library (thanks to [Jarkko Oranen](https://github.com/oranenj))
|
10
|
+
* [#8](https://github.com/voxpupuli/ra10ke/pull/8) Add numeric tag convention support (thanks to [Hervé MARTIN](https://github.com/HerveMARTIN))
|
11
|
+
|
4
12
|
0.2.0
|
5
13
|
-----
|
6
14
|
|
data/README.md
CHANGED
@@ -40,6 +40,18 @@ Ignoring specific modules:
|
|
40
40
|
Under specific conditions you may not wish to report on specific modules being out of date,
|
41
41
|
to ignore a module create `.r10kignore` file in the same directory as your Puppetfile.
|
42
42
|
|
43
|
+
### r10k:solve_dependencies
|
44
|
+
|
45
|
+
Reads the Puppetfile in the current directory and uses the ruby 'solve' library to find
|
46
|
+
missing and outdated dependencies based on their metadata.
|
47
|
+
|
48
|
+
The solver does not allow major version bumps according to SemVer by default. To allow
|
49
|
+
major upgrades, call the rake task with any parameter.
|
50
|
+
|
51
|
+
The rake task will download git modules into the modules/ directory to access their metadata.json.
|
52
|
+
It will also cache forge metadata in ̃$XDG_CACHE_DIR/ra10ke.metadata_cache in order to make subsequent
|
53
|
+
runs faster.
|
54
|
+
|
43
55
|
#### Limitations
|
44
56
|
|
45
57
|
* It works only with modules from the [Forge](https://forge.puppetlabs.com), and Git.
|
data/lib/ra10ke/solve.rb
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'ra10ke/version'
|
4
|
+
require 'git'
|
5
|
+
require 'set'
|
6
|
+
require 'solve'
|
7
|
+
require 'yaml/store'
|
8
|
+
require 'semverse/version'
|
9
|
+
|
10
|
+
# How many versions to fetch from the Forge, at most
|
11
|
+
FETCH_LIMIT = 3
|
12
|
+
|
13
|
+
module Ra10ke::Solve
|
14
|
+
class RakeTask < ::Rake::TaskLib
|
15
|
+
def initialize(*_args)
|
16
|
+
namespace :r10k do
|
17
|
+
desc 'Find missing or outdated module dependencies'
|
18
|
+
task :solve_dependencies, [:allow_major_bump] do |_t, args|
|
19
|
+
require 'r10k/puppetfile'
|
20
|
+
require 'r10k/module/git'
|
21
|
+
require 'r10k/module/metadata_file'
|
22
|
+
require 'puppet_forge'
|
23
|
+
|
24
|
+
allow_major_bump = false
|
25
|
+
allow_major_bump = true if args[:allow_major_bump]
|
26
|
+
|
27
|
+
# Same as in the dependencies task, but oh well.
|
28
|
+
PuppetForge.user_agent = "ra10ke/#{Ra10ke::VERSION}"
|
29
|
+
puppetfile = R10K::Puppetfile.new('.')
|
30
|
+
puppetfile.load!
|
31
|
+
|
32
|
+
# ignore file allows for "don't tell me about this"
|
33
|
+
ignore_modules = []
|
34
|
+
if File.exist?('.r10kignore')
|
35
|
+
ignore_modules = File.readlines('.r10kignore').each(&:chomp!)
|
36
|
+
end
|
37
|
+
# Actual new logic begins here:
|
38
|
+
cache = (ENV['XDG_CACHE_DIR'] || File.expand_path('~/.cache'))
|
39
|
+
# Metadata cache, since the Forge is slow:
|
40
|
+
@metadata_cache = YAML::Store.new File.join(cache, 'ra10ke.metadata_cache')
|
41
|
+
# The graph of available module versions
|
42
|
+
@graph = Solve::Graph.new
|
43
|
+
# Set of modules that we have already added to the graph
|
44
|
+
@processed_modules = Set.new
|
45
|
+
# The set of "demands" we make of the solver. Will be a list of module names
|
46
|
+
# Could also demand certain version constraints to hold, but the code does not do it
|
47
|
+
# Can be either "module-name" or ["module-name", "version-constraint"]
|
48
|
+
@demands = Set.new
|
49
|
+
# List of modules we have in the Puppetfile, as [name, version] pairs
|
50
|
+
@current_modules = []
|
51
|
+
|
52
|
+
puppetfile.modules.each do |puppet_module|
|
53
|
+
next if ignore_modules.include? puppet_module.title
|
54
|
+
if puppet_module.class == R10K::Module::Forge
|
55
|
+
module_name = puppet_module.title.tr('/', '-')
|
56
|
+
installed_version = puppet_module.expected_version
|
57
|
+
puts "Processing Forge module #{module_name}-#{installed_version}"
|
58
|
+
@current_modules << [module_name, installed_version]
|
59
|
+
@graph.artifact(module_name, installed_version)
|
60
|
+
constraint = '>=0.0.0'
|
61
|
+
unless allow_major_bump
|
62
|
+
ver = Semverse::Version.new installed_version
|
63
|
+
if ver.major.zero?
|
64
|
+
constraint = "~>#{installed_version}"
|
65
|
+
else
|
66
|
+
nver = Semverse::Version.new([ver.major + 1, 0, 0])
|
67
|
+
constraint = "<#{nver}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
puts "...Adding a demand: #{module_name} #{constraint}"
|
71
|
+
|
72
|
+
@demands.add([module_name, constraint])
|
73
|
+
puts '...Fetching latest release version information'
|
74
|
+
forge_rel = PuppetForge::Module.find(module_name).current_release
|
75
|
+
mod = @graph.artifact(module_name, forge_rel.version)
|
76
|
+
puts '...Adding its requirements to the graph'
|
77
|
+
meta = get_release_metadata(module_name, forge_rel)
|
78
|
+
add_reqs_to_graph(mod, meta)
|
79
|
+
end
|
80
|
+
|
81
|
+
next unless puppet_module.class == R10K::Module::Git
|
82
|
+
# This downloads the git module to modules/modulename
|
83
|
+
meta = fetch_git_metadata(puppet_module)
|
84
|
+
version = get_key_or_sym(meta, :version)
|
85
|
+
module_name = puppet_module.title.tr('/', '-')
|
86
|
+
@current_modules << [module_name, version]
|
87
|
+
# We should add git modules with exact versions, or the system might recommend updating to a
|
88
|
+
# Forge version.
|
89
|
+
puts "Adding git module #{module_name} to the list of required modules with exact version: #{version}"
|
90
|
+
@demands.add([module_name, version])
|
91
|
+
mod = @graph.artifact(module_name, version)
|
92
|
+
puts "...Adding requirements for git module #{module_name}-#{version}"
|
93
|
+
add_reqs_to_graph(mod, meta)
|
94
|
+
end
|
95
|
+
puts
|
96
|
+
puts 'Resolving dependencies...'
|
97
|
+
if allow_major_bump
|
98
|
+
puts 'WARNING: Potentially breaking updates are allowed for this resolution'
|
99
|
+
end
|
100
|
+
result = Solve.it!(@graph, @demands, sorted: true)
|
101
|
+
puts
|
102
|
+
print_module_diff(@current_modules, result)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_release_metadata(name, release)
|
108
|
+
meta = nil
|
109
|
+
@metadata_cache.transaction do
|
110
|
+
meta = @metadata_cache["#{name}-#{release.version}"]
|
111
|
+
unless meta
|
112
|
+
meta = release.metadata
|
113
|
+
@metadata_cache["#{name}-#{release.version}"] = meta
|
114
|
+
end
|
115
|
+
end
|
116
|
+
meta
|
117
|
+
end
|
118
|
+
|
119
|
+
def fetch_git_metadata(puppet_module)
|
120
|
+
# No caching here. I don't think it's really possible to do in a sane way.
|
121
|
+
puts "Fetching git module #{puppet_module.title}, saving to modules/"
|
122
|
+
puppet_module.sync
|
123
|
+
metadata_path = Pathname.new(puppet_module.full_path) + 'metadata.json'
|
124
|
+
unless metadata_path.exist?
|
125
|
+
puts 'WARNING: metadata.json does not exist, assuming version 0.0.0 and no dependencies'
|
126
|
+
return {
|
127
|
+
version: '0.0.0',
|
128
|
+
name: puppet_module.title,
|
129
|
+
dependencies: []
|
130
|
+
}
|
131
|
+
end
|
132
|
+
metadata = R10K::Module::MetadataFile.new(metadata_path)
|
133
|
+
metadata = metadata.read
|
134
|
+
{
|
135
|
+
version: metadata.version,
|
136
|
+
name: metadata.name,
|
137
|
+
dependencies: metadata.dependencies
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
# Is there a better way? :(
|
142
|
+
def get_key_or_sym(hash, k)
|
143
|
+
hash.fetch(k.to_sym, hash.fetch(k.to_s, nil))
|
144
|
+
end
|
145
|
+
|
146
|
+
# At least puppet-extlib has malformed metadata
|
147
|
+
def get_version_req(dep)
|
148
|
+
req = get_key_or_sym(dep, :version_requirement)
|
149
|
+
req = get_key_or_sym(dep, :version_range) unless req
|
150
|
+
req
|
151
|
+
end
|
152
|
+
|
153
|
+
def print_module_diff(current, resolution)
|
154
|
+
current.sort!
|
155
|
+
resolution.sort!
|
156
|
+
outdated = []
|
157
|
+
missing = []
|
158
|
+
resolution.each do |mod|
|
159
|
+
cur_mod, cur_version = current.shift
|
160
|
+
mod, version = mod
|
161
|
+
if (cur_mod == mod) && cur_version && (cur_version != version)
|
162
|
+
outdated << [mod, cur_version, version]
|
163
|
+
elsif cur_mod != mod
|
164
|
+
missing << [mod, version]
|
165
|
+
current.unshift [cur_mod, cur_version]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
missing.each do |m|
|
169
|
+
puts format('MISSING: %-25s %s', *m)
|
170
|
+
end
|
171
|
+
outdated.each do |o|
|
172
|
+
puts format('OUTDATED: %-25s %s -> %s', *o)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def add_reqs_to_graph(artifact, metadata, no_demands = nil)
|
177
|
+
deps = get_key_or_sym(metadata, :dependencies)
|
178
|
+
my_name = get_key_or_sym(metadata, :name)
|
179
|
+
deps.each do |dep|
|
180
|
+
name = get_key_or_sym(dep, :name).tr('/', '-')
|
181
|
+
# Add dependency to the global set of modules we want, so that we can
|
182
|
+
# actually ask the solver for the versioned thing
|
183
|
+
@demands.add(name) unless no_demands
|
184
|
+
ver = get_version_req(dep)
|
185
|
+
unless ver
|
186
|
+
# no version specified, so anything will do
|
187
|
+
ver = '>=0.0.0'
|
188
|
+
end
|
189
|
+
ver.split(/(?=[<])/).each do |bound|
|
190
|
+
bound.strip!
|
191
|
+
v = begin
|
192
|
+
Semverse::Constraint.new(bound)
|
193
|
+
rescue
|
194
|
+
nil
|
195
|
+
end
|
196
|
+
if v
|
197
|
+
artifact.depends(name, v.to_s)
|
198
|
+
else
|
199
|
+
puts "WARNING: Invalid version constraint: #{bound}"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
# Find the dependency in the forge, unless it's already been processed
|
203
|
+
# and add its releases to the global graph
|
204
|
+
next unless @processed_modules.add?(name)
|
205
|
+
puts "Fetching module info for #{name}"
|
206
|
+
mod = begin
|
207
|
+
PuppetForge::Module.find(name)
|
208
|
+
rescue
|
209
|
+
# It's probably a git module
|
210
|
+
nil
|
211
|
+
end
|
212
|
+
next unless mod # Git module, or non-forge dependency. Skip to next for now.
|
213
|
+
# Fetching metadata for all releases takes ages (which is weird, since it's mostly static info)
|
214
|
+
mod.releases.take(FETCH_LIMIT).each do |rel|
|
215
|
+
meta = get_release_metadata(name, rel)
|
216
|
+
rel_artifact = @graph.artifact(name, rel.version)
|
217
|
+
puts "...Recursively adding requirements for dependency #{name} version #{rel.version}"
|
218
|
+
# We don't want to add the requirements to the list of demands for all versions,
|
219
|
+
# but we need them in the graph to be able to solve dependencies
|
220
|
+
add_reqs_to_graph(rel_artifact, meta, :no_demands)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
Ra10ke::Solve::RakeTask.new
|
data/lib/ra10ke/version.rb
CHANGED
data/lib/ra10ke.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/tasklib'
|
3
3
|
require 'ra10ke/version'
|
4
|
+
require 'ra10ke/solve'
|
4
5
|
require 'git'
|
5
6
|
|
6
7
|
module Ra10ke
|
@@ -52,12 +53,14 @@ module Ra10ke
|
|
52
53
|
when 'sha'
|
53
54
|
latest_ref = remote_refs['head'][:sha]
|
54
55
|
when 'tag'
|
55
|
-
# we have to be opinionated here, due to multiple conventions only
|
56
|
-
#
|
57
|
-
if ref.match(/^[vV]
|
56
|
+
# we have to be opinionated here, due to multiple conventions only the two main will be accepted
|
57
|
+
# v#.#.# or #.#.# is what we will pick.
|
58
|
+
if ref.match(/^[vV]?\d[\.\d]*/)
|
58
59
|
tags = remote_refs['tags']
|
59
|
-
version_tags = tags.select { |f| /^[vV]
|
60
|
+
version_tags = tags.select { |f| /^[vV]?\d[\.\d]*/.match(f) }
|
60
61
|
latest_ref = version_tags.keys.sort.last
|
62
|
+
else
|
63
|
+
latest_ref = "undef (tags don't match v#.#.# or #.#.#)"
|
61
64
|
end
|
62
65
|
else
|
63
66
|
raise "Unable to determine ref_type for #{puppet_module.title}"
|
data/ra10ke.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ra10ke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theo Chatzimichos
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: solve
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
description: R10K and Puppetfile rake tasks
|
70
84
|
email:
|
71
85
|
- tampakrap@gmail.com
|
@@ -79,6 +93,7 @@ files:
|
|
79
93
|
- LICENSE.txt
|
80
94
|
- README.md
|
81
95
|
- lib/ra10ke.rb
|
96
|
+
- lib/ra10ke/solve.rb
|
82
97
|
- lib/ra10ke/version.rb
|
83
98
|
- ra10ke.gemspec
|
84
99
|
homepage: https://github.com/voxpupuli/ra10ke
|
@@ -101,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
116
|
version: '0'
|
102
117
|
requirements: []
|
103
118
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.
|
119
|
+
rubygems_version: 2.6.11
|
105
120
|
signing_key:
|
106
121
|
specification_version: 4
|
107
122
|
summary: Syntax check for the Puppetfile, check for outdated installed puppet modules
|