From 0ccc5499b14e0cfb75ec413f88b60e69214a525e Mon Sep 17 00:00:00 2001 From: Emily Samp Date: Wed, 31 Jan 2024 15:45:05 -0600 Subject: [PATCH] Support filtering RBI files by version in annotations command --- lib/tapioca/commands/annotations.rb | 43 ++++++++++++++++------- spec/tapioca/cli/annotations_spec.rb | 4 +++ spec/tapioca/commands/annotations_spec.rb | 5 ++- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/lib/tapioca/commands/annotations.rb b/lib/tapioca/commands/annotations.rb index fdaef9723..17f1814e1 100644 --- a/lib/tapioca/commands/annotations.rb +++ b/lib/tapioca/commands/annotations.rb @@ -38,22 +38,27 @@ def initialize( sig { override.void } def execute @indexes = fetch_indexes - project_gems = list_gemfile_gems + gem_names_and_versions = list_gemfile_gems - remove_expired_annotations(project_gems) - fetch_annotations(project_gems) + remove_expired_annotations(gem_names_and_versions.keys) + fetch_annotations(gem_names_and_versions) ensure GitAttributes.create_vendored_attribute_file(@outpath) end - sig { returns(T::Array[String]) } + sig { returns(T::Hash[String, ::Gem::Version]) } def list_gemfile_gems say("Listing gems from Gemfile.lock... ", [:blue, :bold]) gemfile = Bundler.read_file("Gemfile.lock") parser = Bundler::LockfileParser.new(gemfile) - gem_names = parser.specs.map(&:name) + + gem_names_and_versions = T.let(Hash.new { |h, k| h[k] = [] }, T::Hash[String, ::Gem::Version]) + parser.specs.each_with_object(gem_names_and_versions) do |spec, hash| + hash[spec.name] = spec.version + end + say("Done", :green) - gem_names + gem_names_and_versions end sig { params(project_gems: T::Array[String]).void } @@ -109,12 +114,12 @@ def fetch_index(repo_uri, repo_number:) index end - sig { params(gem_names: T::Array[String]).returns(T::Array[String]) } - def fetch_annotations(gem_names) + sig { params(gem_names_and_versions: T::Hash[String, ::Gem::Version]).returns(T::Array[String]) } + def fetch_annotations(gem_names_and_versions) say("Fetching gem annotations from central repository... ", [:blue, :bold]) fetchable_gems = T.let(Hash.new { |h, k| h[k] = [] }, T::Hash[String, T::Array[String]]) - gem_names.each_with_object(fetchable_gems) do |gem_name, hash| + gem_names_and_versions.keys.each_with_object(fetchable_gems) do |gem_name, hash| @indexes.each do |uri, index| T.must(hash[gem_name]) << uri if index.has_gem?(gem_name) end @@ -127,13 +132,18 @@ def fetch_annotations(gem_names) end say("\n") - fetched_gems = fetchable_gems.select { |gem_name, repo_uris| fetch_annotation(repo_uris, gem_name) } + fetched_gems = fetchable_gems.select do |gem_name, repo_uris| + gem_version = gem_names_and_versions[gem_name] + next unless gem_version + + fetch_annotation(repo_uris, gem_name, gem_version) + end say("\nDone", :green) fetched_gems.keys.sort end - sig { params(repo_uris: T::Array[String], gem_name: String).void } - def fetch_annotation(repo_uris, gem_name) + sig { params(repo_uris: T::Array[String], gem_name: String, gem_version: ::Gem::Version).void } + def fetch_annotation(repo_uris, gem_name, gem_version) contents = repo_uris.map do |repo_uri| fetch_file(repo_uri, "#{CENTRAL_REPO_ANNOTATIONS_DIR}/#{gem_name}.rbi") end @@ -141,6 +151,7 @@ def fetch_annotation(repo_uris, gem_name) content = merge_files(gem_name, contents.compact) return unless content + content = filter_versions(gem_version, content) content = apply_typed_override(gem_name, content) content = add_header(gem_name, content) @@ -221,6 +232,14 @@ def apply_typed_override(name, content) Spoom::Sorbet::Sigils.update_sigil(content, strictness) end + sig { params(gem_version: ::Gem::Version, content: String).returns(String) } + def filter_versions(gem_version, content) + rbi = RBI::Parser.parse_string(content) + rbi.filter_versions!(gem_version) + + rbi.string + end + sig { params(gem_name: String, contents: T::Array[String]).returns(T.nilable(String)) } def merge_files(gem_name, contents) return if contents.empty? diff --git a/spec/tapioca/cli/annotations_spec.rb b/spec/tapioca/cli/annotations_spec.rb index 1e0cb1c66..01b46af22 100644 --- a/spec/tapioca/cli/annotations_spec.rb +++ b/spec/tapioca/cli/annotations_spec.rb @@ -372,6 +372,7 @@ class Foo; end repo = create_repo({ foo: <<~RBI, # typed: false + # @version > 0.3.5 class AnnotationForFoo; end class Foo; end @@ -384,14 +385,17 @@ class Foo; end assert_project_annotation_equal("sorbet/rbi/annotations/foo.rbi", <<~RBI) # typed: false + # DO NOT EDIT MANUALLY # This file was pulled from a central RBI files repository. # Please run `bin/tapioca annotations` to update it. + class Foo; end RBI assert_success_status(result) + @project.write_gemfile!(@project.tapioca_gemfile) repo.destroy! end end diff --git a/spec/tapioca/commands/annotations_spec.rb b/spec/tapioca/commands/annotations_spec.rb index 24546c31e..c09caf02a 100644 --- a/spec/tapioca/commands/annotations_spec.rb +++ b/spec/tapioca/commands/annotations_spec.rb @@ -58,7 +58,10 @@ class AnnotationsSpec < SpecWithProject gems = T.unsafe(command).stub(:say, ->(*_args) {}) do T.unsafe(command).stub(:create_file, ->(*_args) {}) do - command.send(:fetch_annotations, ["foo", "bar"]) + command.send( + :fetch_annotations, + { "foo" => ::Gem::Version.new("0.1"), "bar" => ::Gem::Version.new("0.1") }, + ) end end