diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml index 3de7288eb..07236db69 100644 --- a/.github/workflows/plugins.yml +++ b/.github/workflows/plugins.yml @@ -15,7 +15,7 @@ permissions: contents: read jobs: - regression: + rails_and_rspec_typechecking: runs-on: ubuntu-latest steps: @@ -44,9 +44,36 @@ jobs: run: bundle exec rbs collection update - name: Ensure typechecking still works run: bundle exec solargraph typecheck --level strong + rails_and_rspec_specs: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.4 # keep same as typecheck.yml + bundler-cache: true + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: yq + version: 1.0 + - name: Install gems + run: | + echo 'gem "solargraph-rails"' > .Gemfile + echo 'gem "solargraph-rspec"' >> .Gemfile + bundle install + bundle update --pre rbs + - name: Configure to use plugins + run: | + bundle exec solargraph config + yq -yi '.plugins += ["solargraph-rails"]' .solargraph.yml + yq -yi '.plugins += ["solargraph-rspec"]' .solargraph.yml + - name: Install gem types + run: bundle exec rbs collection update - name: Ensure specs still run run: bundle exec rake spec - rails: + rails_typechecking: runs-on: ubuntu-latest steps: @@ -57,7 +84,7 @@ jobs: ruby-version: 3.4 # keep same as typecheck.yml # See https://github.com/castwide/solargraph/actions/runs/19000135777/job/54265647107?pr=1119 rubygems: latest - bundler-cache: false + bundler-cache: true - uses: awalsh128/cache-apt-pkgs-action@latest with: packages: yq @@ -75,9 +102,36 @@ jobs: run: bundle exec rbs collection update - name: Ensure typechecking still works run: bundle exec solargraph typecheck --level strong + rails_specs: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.4 # keep same as typecheck.yml + # See https://github.com/castwide/solargraph/actions/runs/19000135777/job/54265647107?pr=1119 + rubygems: latest + bundler-cache: true + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: yq + version: 1.0 + - name: Install gems + run: | + echo 'gem "solargraph-rails"' > .Gemfile + bundle install + bundle update --pre rbs + - name: Configure to use plugins + run: | + bundle exec solargraph config + yq -yi '.plugins += ["solargraph-rails"]' .solargraph.yml + - name: Install gem types + run: bundle exec rbs collection update - name: Ensure specs still run run: bundle exec rake spec - rspec: + rspec_typechecking: runs-on: ubuntu-latest steps: @@ -86,7 +140,7 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: 3.4 # keep same as typecheck.yml - bundler-cache: false + bundler-cache: true - uses: awalsh128/cache-apt-pkgs-action@latest with: packages: yq @@ -104,9 +158,33 @@ jobs: run: bundle exec rbs collection update - name: Ensure typechecking still works run: bundle exec solargraph typecheck --level strong + rspec_specs: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.4 # keep same as typecheck.yml + bundler-cache: true + - uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: yq + version: 1.0 + - name: Install gems + run: | + echo 'gem "solargraph-rspec"' >> .Gemfile + bundle install + bundle update --pre rbs + - name: Configure to use plugins + run: | + bundle exec solargraph config + yq -yi '.plugins += ["solargraph-rspec"]' .solargraph.yml + - name: Install gem types + run: bundle exec rbs collection update - name: Ensure specs still run run: bundle exec rake spec - run_solargraph_rspec_specs: # check out solargraph-rspec as well as this project, and point the former to use the latter as a local gem runs-on: ubuntu-latest @@ -129,7 +207,7 @@ jobs: with: ruby-version: 3.4 rubygems: latest - bundler-cache: false + bundler-cache: true - name: Install gems run: | set -x @@ -184,7 +262,7 @@ jobs: with: # solargraph-rails supports Ruby 3.0+ ruby-version: '3.0' - bundler-cache: false + bundler-cache: true # https://github.com/apiology/solargraph/actions/runs/19400815835/job/55508092473?pr=17 rubygems: latest bundler: latest diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 174a1a6e3..4762f9905 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -71,6 +71,10 @@ jobs: with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true + # see https://github.com/castwide/solargraph/actions/runs/19391419903/job/55485410493?pr=1119 + # + # match version in Gemfile.lock and use same version below + bundler: 2.5.23 - name: Set rbs version run: echo "gem 'rbs', '${{ matrix.rbs-version }}'" >> .Gemfile # /home/runner/.rubies/ruby-head/lib/ruby/gems/3.5.0+2/gems/rbs-3.9.4/lib/rbs.rb:11: @@ -98,9 +102,18 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: '3.4' + # see https://github.com/castwide/solargraph/actions/runs/19391419903/job/55485410493?pr=1119 + # + # match version in Gemfile.lock and use same version below + bundler: 2.5.23 bundler-cache: true + - name: Install gems + run: | + bundle _2.5.23_ install + bundle update rbs # use latest available for this Ruby version - name: Update types - run: bundle exec rbs collection update + run: | + bundle exec rbs collection update - name: Run tests run: bundle exec rake spec - name: Check PR coverage diff --git a/lib/solargraph/api_map.rb b/lib/solargraph/api_map.rb index 88e82a692..66f68533f 100755 --- a/lib/solargraph/api_map.rb +++ b/lib/solargraph/api_map.rb @@ -754,6 +754,13 @@ def qualify_superclass fq_sub_tag store.qualify_superclass fq_sub_tag end + # @param require_path [String] + # + # @return [Array, nil] + def resolve_require require_path + workspace.resolve_require require_path + end + private # A hash of source maps with filename keys. diff --git a/lib/solargraph/diagnostics/base.rb b/lib/solargraph/diagnostics/base.rb index ff91a9062..31b9a4342 100644 --- a/lib/solargraph/diagnostics/base.rb +++ b/lib/solargraph/diagnostics/base.rb @@ -20,8 +20,9 @@ def initialize *args # # @param source [Solargraph::Source] # @param api_map [Solargraph::ApiMap] + # @param workspace [Solargraph::Workspace, nil] # @return [Array] - def diagnose source, api_map + def diagnose source, api_map, workspace: nil [] end end diff --git a/lib/solargraph/diagnostics/type_check.rb b/lib/solargraph/diagnostics/type_check.rb index b1333f9d9..12d4f6c42 100644 --- a/lib/solargraph/diagnostics/type_check.rb +++ b/lib/solargraph/diagnostics/type_check.rb @@ -7,12 +7,12 @@ module Diagnostics # class TypeCheck < Base # @return [Array] - def diagnose source, api_map + def diagnose source, api_map, workspace: nil # return [] unless args.include?('always') || api_map.workspaced?(source.filename) severity = Diagnostics::Severities::ERROR level = args.reverse.find { |a| %w[normal typed strict strong].include?(a) } || :normal # @sg-ignore sensitive typing needs to handle || on nil types - checker = Solargraph::TypeChecker.new(source.filename, api_map: api_map, level: level.to_sym) + checker = Solargraph::TypeChecker.new(source.filename, api_map: api_map, level: level.to_sym, workspace: workspace) checker.problems .sort { |a, b| a.location.range.start.line <=> b.location.range.start.line } .map do |problem| diff --git a/spec/api_map_method_spec.rb b/spec/api_map_method_spec.rb index 87469562b..c5c85884a 100644 --- a/spec/api_map_method_spec.rb +++ b/spec/api_map_method_spec.rb @@ -118,14 +118,17 @@ class B end describe '#get_method_stack' do - let(:out) { StringIO.new } - let(:api_map) { described_class.load_with_cache(Dir.pwd, out) } + let(:api_map) { described_class.load('') } context 'with stdlib that has vital dependencies' do let(:external_requires) { ['yaml'] } let(:method_stack) { api_map.get_method_stack('YAML', 'safe_load', scope: :class) } it 'handles the YAML gem aliased to Psych' do + specs = api_map.resolve_require('yaml') + specs.each { |spec| api_map.cache_gem(spec) } + api_map.catalog bench + expect(method_stack).not_to be_empty end end @@ -135,6 +138,11 @@ class B let(:method_stack) { api_map.get_method_stack('Thor', 'desc', scope: :class) } it 'handles finding Thor.desc' do + specs = api_map.resolve_require('thor') + specs.each { |spec| api_map.cache_gem(spec) } + api_map.catalog bench + + # if this fails you may not have an rbs collection installed expect(method_stack).not_to be_empty end end diff --git a/spec/doc_map_spec.rb b/spec/doc_map_spec.rb index 8ff1e70b1..07ccf78c0 100644 --- a/spec/doc_map_spec.rb +++ b/spec/doc_map_spec.rb @@ -116,7 +116,9 @@ context 'with require as bundle/require' do it 'imports all gems when bundler/require used' do doc_map_with_bundler_require = described_class.new(['bundler/require'], workspace, out: nil) - doc_map_with_bundler_require.cache_doc_map_gems!(nil) + if doc_map_with_bundler_require.pins.length <= plain_doc_map.pins.length + doc_map_with_bundler_require.cache_doc_map_gems!(nil) + end expect(doc_map_with_bundler_require.pins.length - plain_doc_map.pins.length).to be_positive end end diff --git a/spec/language_server/message/extended/check_gem_version_spec.rb b/spec/language_server/message/extended/check_gem_version_spec.rb index 26023f505..02f0b1c4a 100644 --- a/spec/language_server/message/extended/check_gem_version_spec.rb +++ b/spec/language_server/message/extended/check_gem_version_spec.rb @@ -36,6 +36,10 @@ end it 'responds to update actions' do + status = instance_double(Process::Status) + allow(status).to receive(:==).with(0).and_return(true) + allow(Open3).to receive(:capture2).with('gem update solargraph').and_return(['', status]) + host = Solargraph::LanguageServer::Host.new message = described_class.new(host, {}, current: Gem::Version.new('0.0.1')) message.process @@ -52,6 +56,7 @@ } host.receive action end.not_to raise_error + expect(Open3).to have_received(:capture2).with('gem update solargraph') end it 'uses bundler' do diff --git a/spec/library_spec.rb b/spec/library_spec.rb index 9f9ab87dc..a21030c12 100644 --- a/spec/library_spec.rb +++ b/spec/library_spec.rb @@ -59,7 +59,7 @@ def foo(adapter) end it 'returns a Completion' do - library = described_class.new(Solargraph::Workspace.new(Dir.pwd, + library = described_class.new(Solargraph::Workspace.new('', Solargraph::Workspace::Config.new)) library.attach Solargraph::Source.load_string(%( require 'backport' diff --git a/spec/pin/base_spec.rb b/spec/pin/base_spec.rb index 4d4315040..90d9a8850 100644 --- a/spec/pin/base_spec.rb +++ b/spec/pin/base_spec.rb @@ -52,8 +52,14 @@ end it 'deals well with known closure combination issue' do - Solargraph::Shell.new.uncache('yard') - api_map = Solargraph::ApiMap.load_with_cache('.', $stderr) + # if this fails you might not have an rbs collection installed + api_map = Solargraph::ApiMap.load '' + + spec = Gem::Specification.find_by_name('yard') + api_map.cache_gem(spec) + + bench = Solargraph::Bench.new(external_requires: ['yard']) + api_map.catalog bench pins = api_map.get_method_stack('YARD::Docstring', 'parser', scope: :class) expect(pins.length).to eq(1) parser_method_pin = pins.first diff --git a/spec/pin/method_spec.rb b/spec/pin/method_spec.rb index c109746af..0b8e780f8 100644 --- a/spec/pin/method_spec.rb +++ b/spec/pin/method_spec.rb @@ -550,7 +550,9 @@ class Foo # on type. Let's make sure we combine those with anything else # found (e.g., additions from the BigDecimal RBS collection) # without collapsing signatures - api_map = Solargraph::ApiMap.load_with_cache(Dir.pwd, nil) + api_map = Solargraph::ApiMap.load(Dir.pwd) + bench = Solargraph::Bench.new external_requires: ['bigdecimal'] + api_map.catalog(bench) method = api_map.get_method_stack('Integer', '+', scope: :instance).first expect(method.signatures.count).to be > 3 end diff --git a/spec/position_spec.rb b/spec/position_spec.rb index d61b05ce5..300973a15 100644 --- a/spec/position_spec.rb +++ b/spec/position_spec.rb @@ -1,5 +1,3 @@ -# frozen_string_literal: true - describe Solargraph::Position do it 'normalizes arrays into positions' do pos = described_class.normalize([0, 1]) diff --git a/spec/rbs_map/conversions_spec.rb b/spec/rbs_map/conversions_spec.rb index e9dc1ccf8..3d3fee486 100644 --- a/spec/rbs_map/conversions_spec.rb +++ b/spec/rbs_map/conversions_spec.rb @@ -97,7 +97,12 @@ def bar: () -> untyped context 'with standard loads for solargraph project' do before :all do # rubocop:disable RSpec/BeforeAfterAll - @api_map = Solargraph::ApiMap.load_with_cache('.') + @api_map = Solargraph::ApiMap.load('.') + gems = %w[parser ast open3] + bench = Solargraph::Bench.new(workspace: @api_map.workspace, external_requires: gems) + @api_map.catalog(bench) + @api_map.cache_all_for_doc_map! + @api_map.catalog(bench) end let(:api_map) { @api_map } @@ -151,7 +156,9 @@ class Sub < Hash[Symbol, untyped] if Gem::Version.new(RBS::VERSION) >= Gem::Version.new('3.9.1') context 'with method pin for Open3.capture2e' do it 'accepts chdir kwarg' do - api_map = Solargraph::ApiMap.load_with_cache('.', $stdout) + api_map = Solargraph::ApiMap.load('.') + bench = Solargraph::Bench.new(external_requires: ['open3']) + api_map.catalog(bench) method_pin = api_map.pins.find do |pin| pin.is_a?(Solargraph::Pin::Method) && pin.path == 'Open3.capture2e' diff --git a/spec/yard_map/mapper_spec.rb b/spec/yard_map/mapper_spec.rb index 96f71ace6..7c2df2319 100644 --- a/spec/yard_map/mapper_spec.rb +++ b/spec/yard_map/mapper_spec.rb @@ -6,8 +6,8 @@ end def pins_with require - doc_map = Solargraph::DocMap.new([require], @api_map.workspace, out: nil) - doc_map.cache_doc_map_gems!(nil) + doc_map = Solargraph::DocMap.new([require], @api_map.workspace, out: $stderr) + doc_map.cache_doc_map_gems!($stderr) doc_map.pins end @@ -39,9 +39,10 @@ def pins_with require it 'marks correct return type from RuboCop::Options.new' do # Using rubocop because it's a known dependency - pins = pins_with('rubocop').select { |pin| pin.path == 'RuboCop::Options.new' } - expect(pins.map(&:return_type).uniq.map(&:to_s)).to eq(['self']) - expect(pins.flat_map(&:signatures).map(&:return_type).uniq.map(&:to_s)).to eq(['self']) + all_pins = pins_with('open3') + pins = all_pins.select { |pin| pin.path == 'Open3.capture2e' } + expect(pins.map(&:return_type).uniq.map(&:to_s)).to eq(['Array(String, Process::Status)']) + expect(pins.flat_map(&:signatures).map(&:return_type).uniq.map(&:to_s)).to eq(['Array(String, Process::Status)']) end it 'marks non-explicit methods' do diff --git a/spec/yardoc_spec.rb b/spec/yardoc_spec.rb index 6cd575de0..80e8d4764 100644 --- a/spec/yardoc_spec.rb +++ b/spec/yardoc_spec.rb @@ -62,9 +62,18 @@ end it 'is idempotent' do + result = instance_double(Process::Status) + allow(result).to receive(:success?).and_return(true) + allow(Open3).to receive(:capture2e).and_return([output, result]).once do + # write the complete file to simulate successful run + FileUtils.mkdir_p(gem_yardoc_path) + FileUtils.touch(File.join(gem_yardoc_path, 'complete')) + end + described_class.build_docs(gem_yardoc_path, [], gemspec) described_class.build_docs(gem_yardoc_path, [], gemspec) # second time - expect(File.exist?(File.join(gem_yardoc_path, 'complete'))).to be true + + expect(Open3).to have_received(:capture2e).once end context 'with an error from yard' do