diff --git a/lib/pyxis/commands/components.rb b/lib/pyxis/commands/components.rb index d85de1a..a5fb286 100644 --- a/lib/pyxis/commands/components.rb +++ b/lib/pyxis/commands/components.rb @@ -3,7 +3,19 @@ module Pyxis module Commands class Components < Thor - desc 'update COMPONENT', 'Update a component in reticulum' + desc 'info [BUILD_ID]', 'Get the component versions for a reticulum build' + def info(build_id) + component_versions = ManagedVersioning::ComponentInfo.new(build_id).execute + + SemanticLogger.flush + + puts 'Versions of each component' + component_versions.each do |component, version| + puts "#{component}: #{version}" + end + end + + desc 'update [COMPONENT]', 'Update a component in reticulum' def update(component) updater(component).execute end @@ -11,9 +23,7 @@ def update(component) desc 'list', 'List all available components' def list puts 'Available components:' - Pyxis::Project.constants.each do |project| - next if project == :Base - + Pyxis::Project.components.each do |project| puts "- #{project.downcase}" end end diff --git a/lib/pyxis/gitlab_client.rb b/lib/pyxis/gitlab_client.rb new file mode 100644 index 0000000..0118023 --- /dev/null +++ b/lib/pyxis/gitlab_client.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Pyxis + class GitlabClient + include SemanticLogger::Loggable + + GITLAB_URL = 'https://gitlab.com' + + CLIENT_CONFIGS = { + release_tools: { + private_token: ENV.fetch('PYXIS_GL_RELEASE_TOOLS_PRIVATE_TOKEN'), + user_id: 20643824, + }, + }.freeze + + def self.client(instance = :release_tools) + CLIENT_CONFIGS[instance][:client] ||= create_client(instance) + end + + def self.create_client(instance) + logger.info('Creating gitlab client', instance: instance) + + client_config = CLIENT_CONFIGS[instance] + options = { + url: GITLAB_URL, + headers: { + 'Private-Token': File.read(client_config[:private_token]), + }, + } + faraday = Faraday.new(options) + faraday.use Pyxis::DryRunEnforcer::FaradayBlocker + faraday.use Pyxis::Logger::FaradayLogger + + enhance_faraday(faraday) + + faraday + end + + def self.enhance_faraday(faraday) + %i[get post put patch delete].each do |method| + faraday.define_singleton_method(:"#{method}_json") do |*args, **kwargs| + response = faraday.send(method, *args, **kwargs) + json = response.body.blank? ? nil : JSON.parse(response.body) + + if json.is_a?(Hash) + Thor::CoreExt::HashWithIndifferentAccess.new(json) + else + json || response + end + end + end + end + end +end diff --git a/lib/pyxis/managed_versioning/component_info.rb b/lib/pyxis/managed_versioning/component_info.rb new file mode 100644 index 0000000..8b0a01b --- /dev/null +++ b/lib/pyxis/managed_versioning/component_info.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Pyxis + module ManagedVersioning + class ComponentInfo + include SemanticLogger::Loggable + + attr_reader :build_id + + def initialize(build_id) + @build_id = build_id + end + + def execute + pipeline = GitlabClient.client.get_json( + "/api/v4/projects/#{Project::Reticulum.api_gitlab_path}/pipelines/#{build_id}" + ) + reticulum_sha = pipeline.sha + + components = {} + + Pyxis::Project.components.each do |project_name| + component_project_class = Pyxis::Project.const_get(project_name) + version_file = "versions/#{component_project_class.component_name}" + + begin + version_content = GithubClient.octokit.contents(Project::Reticulum.github_path, path: version_file, + ref: reticulum_sha) + version = Base64.decode64(version_content.content) + components[component_project_class.component_name] = version + rescue Octokit::NotFound + logger.warn("Version file not found for #{component_project_class.component_name} at SHA #{reticulum_sha}") + end + end + + components + end + end + end +end diff --git a/lib/pyxis/project/base.rb b/lib/pyxis/project/base.rb index 11baf0d..7c55116 100644 --- a/lib/pyxis/project/base.rb +++ b/lib/pyxis/project/base.rb @@ -16,11 +16,19 @@ def github_path paths[:github] end + def api_gitlab_path + paths[:gitlab].gsub('/', '%2F') + end + def component_name # noinspection RubyNilAnalysis name.split('::').last.downcase end end end + + def self.components + constants.reject { |c| %i[Base Reticulum].include?(c) } + end end end