lib/ra10ke/dependencies.rb in ra10ke-1.2.0 vs lib/ra10ke/dependencies.rb in ra10ke-2.0.0
- old
+ new
@@ -1,39 +1,149 @@
+require 'semverse'
+require 'r10k/puppetfile'
+require 'puppet_forge'
+require 'table_print'
+require 'git'
+
module Ra10ke::Dependencies
- @@version_formats = {}
+ class Verification
- # Registers a block that finds the latest version.
- # The block will be called with a list of tags.
- # If the block returns nil the next format will be tried.
- def self.register_version_format(name, &block)
- @@version_formats[name] = block
- end
+ def self.version_formats
+ @version_formats ||= {}
+ end
- # semver is the default version format.
- register_version_format(:semver) do |tags|
- latest_tag = tags.map do |tag|
- begin
- Semverse::Version.new tag[/\Av?(.*)\Z/, 1]
- rescue Semverse::InvalidVersionFormat
- # ignore tags that do not comply to semver
- nil
+ # Registers a block that finds the latest version.
+ # The block will be called with a list of tags.
+ # If the block returns nil the next format will be tried.
+ def self.register_version_format(name, &block)
+ version_formats[name] = block
+ end
+
+ Ra10ke::Dependencies::Verification.register_version_format(:semver) do |tags|
+ latest_tag = tags.map do |tag|
+ begin
+ Semverse::Version.new tag[/\Av?(.*)\Z/, 1]
+ rescue Semverse::InvalidVersionFormat
+ # ignore tags that do not comply to semver
+ nil
+ end
+ end.select { |tag| !tag.nil? }.sort.last.to_s.downcase
+ latest_ref = tags.detect { |tag| tag[/\Av?(.*)\Z/, 1] == latest_tag }
+ end
+ attr_reader :puppetfile
+
+ def initialize(pfile)
+ @puppetfile = pfile
+ # semver is the default version format.
+
+ puppetfile.load!
+ end
+
+ def get_latest_ref(remote_refs)
+ tags = remote_refs['tags'].keys
+ latest_ref = nil
+ self.class.version_formats.detect { |_, block| latest_ref = block.call(tags) }
+ latest_ref = 'undef (tags do not follow any known pattern)' if latest_ref.nil?
+ latest_ref
+ end
+
+ def ignored_modules
+ # ignore file allows for "don't tell me about this"
+ @ignored_modules ||= begin
+ File.readlines('.r10kignore').each {|l| l.chomp!} if File.exist?('.r10kignore')
+ end || []
+ end
+
+ # @summary creates an array of module hashes with version info
+ # @param {Object} supplied_puppetfile - the parsed puppetfile object
+ # @returns {Array} array of version info for each module
+ # @note does not include ignored modules or modules up2date
+ def processed_modules(supplied_puppetfile = puppetfile)
+ threads = []
+ threads = supplied_puppetfile.modules.map do |puppet_module|
+ Thread.new do
+ begin
+ next if ignored_modules.include? puppet_module.title
+ if puppet_module.class == ::R10K::Module::Forge
+ module_name = puppet_module.title.gsub('/', '-')
+ forge_version = ::PuppetForge::Module.find(module_name).current_release.version
+ installed_version = puppet_module.expected_version
+ {
+ name: puppet_module.title,
+ installed: installed_version,
+ latest: forge_version,
+ type: 'forge',
+ message: installed_version != forge_version ? :outdated : :current
+ }
+
+ elsif puppet_module.class == R10K::Module::Git
+ # use helper; avoid `desired_ref`
+ # we do not want to deal with `:control_branch`
+ ref = puppet_module.version
+ next unless ref
+
+ remote = puppet_module.instance_variable_get(:@remote)
+ remote_refs = Git.ls_remote(remote)
+
+ # skip if ref is a branch
+ next if remote_refs['branches'].key?(ref)
+
+ if remote_refs['tags'].key?(ref)
+ # there are too many possible versioning conventions
+ # we have to be be opinionated here
+ # so semantic versioning (vX.Y.Z) it is for us
+ # as well as support for skipping the leading v letter
+ #
+ # register own version formats with
+ # Ra10ke::Dependencies.register_version_format(:name, &block)
+ latest_ref = get_latest_ref(remote_refs)
+ elsif ref.match(/^[a-z0-9]{40}$/)
+ ref = ref.slice(0,8)
+ # for sha just assume head should be tracked
+ latest_ref = remote_refs['head'][:sha].slice(0,8)
+ else
+ raise "Unable to determine ref type for #{puppet_module.title}"
+ end
+ {
+ name: puppet_module.title,
+ installed: ref,
+ latest: latest_ref,
+ type: 'git',
+ message: ref != latest_ref ? :outdated : :current
+ }
+
+ end
+ rescue R10K::Util::Subprocess::SubprocessError => e
+ {
+ name: puppet_module.title,
+ installed: nil,
+ latest: nil,
+ type: :error,
+ message: e.message
+ }
+ end
+ end
end
- end.select { |tag| !tag.nil? }.sort.last.to_s.downcase
- latest_ref = tags.detect { |tag| tag[/\Av?(.*)\Z/, 1] == latest_tag }
- end
+ threads.map { |th| th.join.value }.compact
+ end
- def get_latest_ref(remote_refs)
- tags = remote_refs['tags'].keys
- latest_ref = nil
- @@version_formats.detect { |_, block| latest_ref = block.call(tags) }
- latest_ref = 'undef (tags do not follow any known pattern)' if latest_ref.nil?
- latest_ref
+ def outdated(supplied_puppetfile = puppetfile)
+ processed_modules.find_all do | mod |
+ mod[:message] == :outdated
+ end
+ end
+
+ def print_table(mods)
+ puts
+ tp mods, { name: { width: 50 } }, :installed, :latest, :type, :message
+ end
end
- def define_task_dependencies(*_args)
- desc "Print outdated forge modules"
- task :dependencies do
+ def define_task_print_git_conversion(*_args)
+ desc "Convert and print forge modules to git format"
+ task :print_git_conversion do
+ require 'ra10ke/git_repo'
require 'r10k/puppetfile'
require 'puppet_forge'
PuppetForge.user_agent = "ra10ke/#{Ra10ke::VERSION}"
puppetfile = get_puppetfile
@@ -43,51 +153,42 @@
# ignore file allows for "don't tell me about this"
ignore_modules = []
if File.exist?('.r10kignore')
ignore_modules = File.readlines('.r10kignore').each {|l| l.chomp!}
end
-
- puppetfile.modules.each do |puppet_module|
- next if ignore_modules.include? puppet_module.title
- if puppet_module.class == R10K::Module::Forge
- module_name = puppet_module.title.gsub('/', '-')
- forge_version = PuppetForge::Module.find(module_name).current_release.version
- installed_version = puppet_module.expected_version
- if installed_version != forge_version
- puts "#{puppet_module.title} is OUTDATED: #{installed_version} vs #{forge_version}"
+ forge_mods = puppetfile.modules.find_all { |mod| mod.instance_of?(R10K::Module::Forge) && mod.v3_module.homepage_url? }
+
+ threads = forge_mods.map do |mod|
+ Thread.new do
+ source_url = mod.v3_module.attributes.dig(:current_release, :metadata, :source) || mod.v3_module.homepage_url
+ # git:// does not work with ls-remote command, convert to https
+ source_url = source_url.gsub('git://', 'https://')
+ source_url = source_url.gsub(/\Agit\@(.*)\:(.*)/) do
+ "https://#{$1}/#{$2}"
end
- end
+ repo = ::Ra10ke::GitRepo.new(source_url)
+ ref = repo.get_ref_like(mod.expected_version)
+ ref_name = ref ? ref[:name] : "bad url or tag #{mod.expected_version} is missing"
+ <<~EOF
+ mod '#{mod.name}',
+ :git => '#{source_url}',
+ :ref => '#{ref_name}'
- if puppet_module.class == R10K::Module::Git
- # use helper; avoid `desired_ref`
- # we do not want to deal with `:control_branch`
- ref = puppet_module.version
- next unless ref
-
- remote = puppet_module.instance_variable_get(:@remote)
- remote_refs = Git.ls_remote(remote)
-
- # skip if ref is a branch
- next if remote_refs['branches'].key?(ref)
-
- if remote_refs['tags'].key?(ref)
- # there are too many possible versioning conventions
- # we have to be be opinionated here
- # so semantic versioning (vX.Y.Z) it is for us
- # as well as support for skipping the leading v letter
- #
- # register own version formats with
- # Ra10ke::Dependencies.register_version_format(:name, &block)
- latest_ref = get_latest_ref(remote_refs)
- elsif ref.match(/^[a-z0-9]{40}$/)
- # for sha just assume head should be tracked
- latest_ref = remote_refs['head'][:sha]
- else
- raise "Unable to determine ref type for #{puppet_module.title}"
- end
-
- puts "#{puppet_module.title} is OUTDATED: #{ref} vs #{latest_ref}" if ref != latest_ref
+ EOF
end
end
+ output = threads.map { |th| th.join.value }
+ puts output
+ end
+ end
+
+ def define_task_dependencies(*_args)
+ desc "Print outdated forge modules"
+ task :dependencies do
+ PuppetForge.user_agent = "ra10ke/#{Ra10ke::VERSION}"
+ puppetfile = get_puppetfile
+ PuppetForge.host = puppetfile.forge if puppetfile.forge =~ /^http/
+ dependencies = Ra10ke::Dependencies::Verification.new(puppetfile)
+ dependencies.print_table(dependencies.outdated)
end
end
end