bundler-alive 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2a89085af5b9f1ee492cdbbe0e51fc27026c90760f77ebe0e7aa219b038d423
4
- data.tar.gz: 619562e866a25a255516cbaaedf1a0ccc08c741d3f00bd6c5bd86455793d9db5
3
+ metadata.gz: cf64468693c247f87a2ffbce58960dd82d1313614d1433d0d032210f080e8fd4
4
+ data.tar.gz: a3d9f48ce1e8a932ae954897448acf7ab5cc82123992bd82b72ab33b7a8902b0
5
5
  SHA512:
6
- metadata.gz: 5929a845890c5b50b6bd629296f4bd3f1c457791c6938f53203f464f99ac86634122500cd2e0dc5fc4276e42ef04ba30898ad91ede8546eb2c2cdf8fc9f6ac18
7
- data.tar.gz: 4845907f1e0eedab0c1746a186dc613d31f2e680b8b0f24c08aa660dbd9467840c42a240cb22ab97e9ba46594be185158ae8c8f69752f4f7150585b849e239da
6
+ metadata.gz: 0c4d5747e3b1a133bcc8e1d757fb0ca790b280c667b7f2aa865c95363db66a878f2b0383d436a3b83cb43c19b28d06815c226d7fde09411d626ecdbc0508836f
7
+ data.tar.gz: e4ad9d70fb50258517e8cfbde02aea45435575e0e41435a26e9c5e35141b6df5e71bbebd85f11837afc6fdaa2b76c89508191234417214471f64c18b43d5f8d9
data/.rspec CHANGED
@@ -2,3 +2,4 @@
2
2
  --color
3
3
  --warnings
4
4
  --require spec_helper
5
+ --backtrace
data/Gemfile CHANGED
@@ -17,7 +17,11 @@ group :development do
17
17
  end
18
18
 
19
19
  group :test do
20
- gem "simplecov"
20
+ # Workaround for cc-test-reporter with SimpleCov 0.18.
21
+ # Stop upgrading SimpleCov until the following issue will be resolved.
22
+ # https://github.com/codeclimate/test-reporter/issues/418
23
+ gem "factory_bot"
24
+ gem "simplecov", "~> 0.10", "< 0.18"
21
25
  gem "vcr"
22
26
  gem "webmock"
23
27
  end
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # bundler-alive
2
2
 
3
- ![bundler-alive](https://github.com/kyoshidajp/bundler-alive/actions/workflows/ci.yml/badge.svg)
4
3
  [![Gem Version](https://badge.fury.io/rb/bundler-alive.svg)](https://badge.fury.io/rb/bundler-alive)
4
+ ![bundler-alive](https://github.com/kyoshidajp/bundler-alive/actions/workflows/ci.yml/badge.svg)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/a79d53257bc5e93842f6/maintainability)](https://codeclimate.com/github/kyoshidajp/bundler-alive/maintainability)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/a79d53257bc5e93842f6/test_coverage)](https://codeclimate.com/github/kyoshidajp/bundler-alive/test_coverage)
5
7
 
6
8
  `bunder-alive` checks if gems in a RubyGem's `Gemfile.lock` are active.
7
9
 
@@ -17,10 +19,17 @@ $ gem install bunlder-alive
17
19
 
18
20
  ```
19
21
  $ bundle-alive
22
+ 6 gems are in Gemfile.lock
23
+ ..W....
24
+ Get all source code repository URLs of gems are done!
25
+ .....
20
26
  Name: journey
21
27
  URL: http://github.com/rails/journey
22
28
  Status: false
23
29
 
30
+ Gem: bundle-alive is not found in RubyGems.org.
31
+
32
+ Total: 6 (Dead: 1, Alive: 4, Unknown: 1)
24
33
  Not alive gems are found!
25
34
  ```
26
35
 
@@ -30,7 +39,7 @@ Default `Gemfile.lock` location is in your current directory. You can specify it
30
39
  $ bundle-alive -G /path/to/Gemfile.lock
31
40
  ```
32
41
 
33
- In most cases, the following error is output.
42
+ In some cases, the following error is output.
34
43
 
35
44
  ```
36
45
  Too many requested! Retry later.
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler"
4
+
5
+ module Bundler
6
+ module Alive
7
+ #
8
+ # Announces check progress
9
+ #
10
+ class Announcer
11
+ DOT = "."
12
+
13
+ private_constant :DOT
14
+
15
+ #
16
+ # A new instance of Reporter
17
+ #
18
+ def initialize
19
+ @output = $stdout
20
+ end
21
+
22
+ def announce
23
+ output.write DOT
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :output
29
+ end
30
+ end
31
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "bundler/alive"
4
4
  require "bundler/alive/doctor"
5
+ require "bundler/alive/reportable"
5
6
 
6
7
  require "thor"
7
8
 
@@ -17,19 +18,17 @@ module Bundler
17
18
  desc "check [DIR]", "Checks the Gemfile.lock"
18
19
  method_option :gemfile_lock, type: :string, aliases: "-G",
19
20
  default: "Gemfile.lock"
21
+ method_option :result, type: :string, aliases: "-r",
22
+ default: "result.toml"
20
23
 
21
24
  def check(_dir = Dir.pwd)
22
- doctor = check_by_doctor
25
+ extend Reportable
26
+ report = check_by_doctor
27
+ report.save_as_file(options[:result])
28
+ print_report(report)
23
29
 
24
- if doctor.rate_limit_exceeded_error
25
- puts "Too many requested! Retry later."
26
- exit 1
27
- end
28
-
29
- exit 0 if doctor.all_alive
30
-
31
- puts "Not alive gems are found!"
32
- exit 1
30
+ exit_status = report.result.all_alive? ? 0 : 1
31
+ exit exit_status
33
32
  end
34
33
 
35
34
  desc "version", "Prints the bundler-alive version"
@@ -41,15 +40,12 @@ module Bundler
41
40
 
42
41
  def check_by_doctor
43
42
  doctor = begin
44
- Doctor.new(options[:gemfile_lock])
43
+ Doctor.new(options[:gemfile_lock], options[:result])
45
44
  rescue Bundler::GemfileLockNotFound
46
45
  exit 1
47
46
  end
48
47
 
49
48
  doctor.diagnose
50
- doctor.report
51
- doctor.save_as_file
52
- doctor
53
49
  end
54
50
  end
55
51
  end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+
6
+ module Bundler
7
+ module Alive
8
+ module Client
9
+ #
10
+ # RubyGems.org API Client
11
+ #
12
+ # @see https://guides.rubygems.org/rubygems-org-api/
13
+ #
14
+ class GemsApiClient
15
+ #
16
+ # Not found in rubygems.org error
17
+ #
18
+ class NotFound < StandardError
19
+ end
20
+
21
+ def initialize
22
+ @error_messages = []
23
+ end
24
+
25
+ #
26
+ # Gets gems from RubyGems.org
27
+ #
28
+ # @param [Array<String>] gem_names
29
+ #
30
+ # @return [Client::GemsApiResponse]
31
+ #
32
+ def gems_api_response(gem_names, &block)
33
+ urls = service_with_urls(gem_names, &block)
34
+ $stdout.puts <<~MESSAGE
35
+
36
+ Get all source code repository URLs of gems are done!
37
+ MESSAGE
38
+ Client::GemsApiResponse.new(
39
+ service_with_urls: urls,
40
+ error_messages: error_messages
41
+ )
42
+ end
43
+
44
+ private
45
+
46
+ attr_accessor :error_messages
47
+
48
+ def api_url(gem_name)
49
+ "https://rubygems.org/api/v1/gems/#{gem_name}.json"
50
+ end
51
+
52
+ def connection
53
+ Faraday.new do |connection|
54
+ connection.adapter :net_http
55
+ end
56
+ end
57
+
58
+ def service_with_urls(gem_names, &block)
59
+ urls = get_repository_urls(gem_names, &block)
60
+ urls.each_with_object({}) do |url, hash|
61
+ service_name = url.service_name
62
+ hash[service_name] = Array(hash[service_name]) << url
63
+ end
64
+ end
65
+
66
+ #
67
+ # Returns repository url
68
+ #
69
+ # @param [String] gem_name
70
+ #
71
+ # @return [SourceCodeRepositoryUrl]
72
+ #
73
+ def get_repository_url(gem_name)
74
+ url = api_url(gem_name)
75
+ response = connection.get(url)
76
+
77
+ raise NotFound, "Gem: #{gem_name} is not found in RubyGems.org." unless response.success?
78
+
79
+ body = JSON.parse(response.body)
80
+ raw_url = source_code_url(body: body, gem_name: gem_name)
81
+ SourceCodeRepositoryUrl.new(raw_url, gem_name)
82
+ end
83
+
84
+ def source_code_url(body:, gem_name:)
85
+ url = body["source_code_uri"]
86
+ return url if SourceCodeRepositoryUrl.support_url?(url)
87
+
88
+ url = body["homepage_uri"]
89
+ return url if SourceCodeRepositoryUrl.support_url?(url)
90
+
91
+ raise NotFound, "[#{gem_name}] source code repository is not found in RubyGems.org."
92
+ end
93
+
94
+ def get_repository_urls(gem_names)
95
+ result = gem_names.map do |gem_name|
96
+ yield if block_given?
97
+ get_repository_url(gem_name)
98
+ rescue StandardError => e
99
+ $stdout.write "W"
100
+ error_messages << e.message
101
+ end
102
+
103
+ result.find_all { |obj| obj.instance_of?(Alive::SourceCodeRepositoryUrl) }
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module Alive
5
+ module Client
6
+ #
7
+ # Represents API Response of RubyGems.org
8
+ #
9
+ class GemsApiResponse
10
+ attr_reader :service_with_urls, :error_messages
11
+
12
+ #
13
+ # Creates a new StatusResult instance
14
+ #
15
+ # @param [StatusCollection|nil] :collection
16
+ # @param [Array] :error_messages
17
+ #
18
+ # @return [GemsApiResponse]
19
+ #
20
+ def initialize(service_with_urls:, error_messages:)
21
+ @service_with_urls = service_with_urls
22
+ @error_messages = error_messages
23
+
24
+ freeze
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -9,9 +9,36 @@ module Bundler
9
9
  #
10
10
  # API Client for GitHub API
11
11
  #
12
+ # @see https://docs.github.com/en/rest/search#search-repositories
13
+ #
12
14
  module GitHubApi
15
+ # Environment variable name of GitHub Access Token
13
16
  ACCESS_TOKEN_ENV_NAME = "BUNDLER_ALIVE_GITHUB_TOKEN"
14
17
 
18
+ # Separator of query condition
19
+ QUERY_CONDITION_SEPARATOR = " "
20
+
21
+ # Number of attempts to request after too many requests
22
+ RETRIES_ON_TOO_MANY_REQUESTS = 3
23
+
24
+ # Interval second when retrying request
25
+ RETRY_INTERVAL_SEC_ON_TOO_MANY_REQUESTS = 120
26
+
27
+ #
28
+ # Max number of conditional operator at once
29
+ #
30
+ # @see https://docs.github.com/en/rest/search#limitations-on-query-length
31
+ QUERY_MAX_OPERATORS_AT_ONCE = 6
32
+
33
+ private_constant :QUERY_MAX_OPERATORS_AT_ONCE
34
+
35
+ def self.extended(base)
36
+ base.instance_eval do
37
+ @rate_limit_exceeded = false
38
+ @retries_on_too_many_requests = 0
39
+ end
40
+ end
41
+
15
42
  #
16
43
  # Creates a GitHub client
17
44
  #
@@ -22,39 +49,112 @@ module Bundler
22
49
  end
23
50
 
24
51
  #
25
- # Returns repository URL is archived?
52
+ # Query repository statuses
53
+ #
54
+ # @param [Array<RepositoryUrl>] :urls
55
+ #
56
+ # @return [StatusResult]
57
+ #
58
+ # rubocop:disable Metrics/MethodLength
59
+ def query(urls:)
60
+ collection = StatusCollection.new
61
+ name_with_archived = get_name_with_statuses(urls)
62
+ urls.each do |url|
63
+ yield if block_given?
64
+
65
+ gem_name = url.gem_name
66
+ alive = !name_with_archived[gem_name]
67
+ status = Status.new(name: gem_name, repository_url: url, alive: alive, checked_at: Time.now)
68
+ collection = collection.add(gem_name, status)
69
+ end
70
+
71
+ StatusResult.new(collection: collection, error_messages: @error_messages,
72
+ rate_limit_exceeded: @rate_limit_exceeded)
73
+ end
74
+ # rubocop:enable Metrics/MethodLength
75
+
76
+ private
77
+
78
+ #
79
+ # Search status of repositories
26
80
  #
27
- # @param [SourceCodeRepositoryUrl] repository_url
81
+ # @param [Array<RepositoryUrl>] urls
28
82
  #
29
- # @raise [ArgumentError]
30
- # when repository_uri is not `SourceCodeRepositoryUrl`
83
+ # @return [Hash<String, Boolean>]
84
+ # gem name with archived or not
85
+ #
86
+ # rubocop:disable Metrics/MethodLength
87
+ def get_name_with_statuses(urls)
88
+ raise ArgumentError unless urls.instance_of?(Array)
89
+
90
+ name_with_status = {}
91
+ urls.each_slice(QUERY_MAX_OPERATORS_AT_ONCE) do |sliced_urls|
92
+ q = search_query(sliced_urls)
93
+ repositories = search_repositories_with_retry(q)
94
+ next if repositories.nil?
95
+
96
+ repositories.each do |repository|
97
+ name = repository["name"]
98
+ name_with_status[name] = repository["archived"]
99
+ end
100
+ end
101
+ name_with_status
102
+ end
103
+ # rubocop:enable Metrics/MethodLength
104
+
105
+ #
106
+ # Search query of repositories
107
+ #
108
+ # @param [Array<RepositoryUrl>] urls
109
+ #
110
+ # @return [String]
111
+ #
112
+ def search_query(urls)
113
+ urls.map do |url|
114
+ "repo:#{slug(url.url)}"
115
+ end.join(QUERY_CONDITION_SEPARATOR)
116
+ end
117
+
118
+ #
119
+ # Search repositories
120
+ #
121
+ # @param [String] query
31
122
  #
32
123
  # @raise [Octokit::TooManyRequests]
33
124
  # when too many requested to GitHub.com
34
- #
35
125
  # @raise [SourceCodeClient::SearchRepositoryError]
36
126
  # when Error without `Octokit::TooManyRequests`
37
127
  #
38
- # @return [Boolean]
128
+ # @return [Array<Sawyer::Resource>|nil]
39
129
  #
40
- # rubocop:disable Metrics/MethodLength
41
- def archived?(repository_url)
42
- unless repository_url.instance_of?(SourceCodeRepositoryUrl)
43
- raise ArgumentError, "UnSupported url: #{repository_url}"
130
+ def search_repositories(query)
131
+ result = @client.search_repositories(query)
132
+ result[:items]
133
+ rescue Octokit::TooManyRequests => e
134
+ raise e
135
+ rescue StandardError => e
136
+ @error_messages << e.message
137
+ []
138
+ end
139
+
140
+ def search_repositories_with_retry(query)
141
+ search_repositories(query)
142
+ rescue Octokit::TooManyRequests
143
+ if @retries_on_too_many_requests < RETRIES_ON_TOO_MANY_REQUESTS
144
+ @retries_on_too_many_requests += 1
145
+ sleep_with_message
146
+ retry
44
147
  end
45
148
 
46
- query = "repo:#{slug(repository_url.url)}"
149
+ @rate_limit_exceeded = true
150
+ []
151
+ end
47
152
 
48
- begin
49
- result = @client.search_repositories(query)
50
- result[:items][0][:archived]
51
- rescue Octokit::TooManyRequests => e
52
- raise SourceCodeClient::RateLimitExceededError, e.message
53
- rescue StandardError => e
54
- raise SourceCodeClient::SearchRepositoryError, e.message
55
- end
153
+ def sleep_with_message
154
+ puts "Too many requested. Sleep #{RETRY_INTERVAL_SEC_ON_TOO_MANY_REQUESTS} sec."
155
+ sleep RETRY_INTERVAL_SEC_ON_TOO_MANY_REQUESTS
156
+ puts "Retry request (#{@retries_on_too_many_requests}/#{RETRIES_ON_TOO_MANY_REQUESTS})"
56
157
  end
57
- # rubocop:enable Metrics/MethodLength
58
158
 
59
159
  #
60
160
  # Returns slug of repository URL
@@ -7,9 +7,11 @@ module Bundler
7
7
  # Represents a source code client
8
8
  #
9
9
  class SourceCodeClient
10
+ # Error of searching repository
10
11
  class SearchRepositoryError < StandardError
11
12
  end
12
13
 
14
+ # Error of rate limit exceeded
13
15
  class RateLimitExceededError < StandardError
14
16
  end
15
17
 
@@ -31,10 +33,11 @@ module Bundler
31
33
  def initialize(service_name:)
32
34
  raise ArgumentError, "Unknown service: #{service_name}" unless SERVICE_WITH_STRATEGIES.key?(service_name)
33
35
 
34
- service = SERVICE_WITH_STRATEGIES[service_name]
35
- extend service
36
+ strategy = SERVICE_WITH_STRATEGIES[service_name]
37
+ extend strategy
36
38
 
37
39
  @client = create_client
40
+ @error_messages = []
38
41
 
39
42
  super()
40
43
  end
@@ -10,113 +10,118 @@ module Bundler
10
10
  # Diagnoses a `Gemfile.lock` with a TOML file
11
11
  #
12
12
  class Doctor
13
- attr_reader :all_alive, :rate_limit_exceeded_error
14
-
15
13
  #
16
14
  # A new instance of Doctor
17
15
  #
18
16
  # @param [String] lock_file lock file of gem
19
17
  # @param [String] result_file file of result
20
18
  #
21
- def initialize(lock_file, result_file = "result.toml")
19
+ def initialize(lock_file, result_file)
22
20
  @lock_file = lock_file
23
21
  @result_file = result_file
24
- @gem_client = Client::GemsApi.new
22
+ @gem_client = Client::GemsApiClient.new
25
23
  @result = nil
26
- @all_alive = nil
27
- @rate_limit_exceeded_error = false
24
+ @rate_limit_exceeded = false
25
+ @announcer = Announcer.new
26
+ @error_messages = []
28
27
  end
29
28
 
30
29
  #
31
30
  # Diagnoses gems in lock file of gem
32
31
  #
32
+ # @raise [Client::SourceCodeClient::RateLimitExceededError]
33
+ # When exceeded access rate limit
34
+ #
35
+ # @raise [StandardError]
36
+ # When raised unexpected error
37
+ #
38
+ # @return [Report]
39
+ #
33
40
  def diagnose
34
- @result = gems.each_with_object(GemStatusCollection.new) do |spec, collection|
35
- gem_name = spec.name
36
- gem_status = diagnose_gem(gem_name)
37
-
38
- collection.add(gem_name, gem_status)
39
- end
41
+ $stdout.puts "#{collection_from_gemfile.total_size} gems are in Gemfile.lock"
42
+ result = _diagnose
43
+ Report.new(result)
40
44
  end
41
45
 
46
+ private
47
+
48
+ attr_reader :lock_file, :result_file, :gem_client, :announcer,
49
+ :result, :error_messages, :rate_limit_exceeded
50
+
42
51
  #
43
- # Reports the result
52
+ # @return [Array<String>]
44
53
  #
45
- def report
46
- need_to_report_gems = result.need_to_report_gems
47
- @all_alive = need_to_report_gems.size.zero?
48
- need_to_report_gems.each do |_name, gem_status|
49
- print gem_status.report
54
+ def no_need_to_get_gems
55
+ return [] unless File.exist?(result_file)
56
+
57
+ toml_hash = TomlRB.load_file(result_file)
58
+ toml_hash.each_with_object([]) do |(gem_name, v), array|
59
+ alive = v["alive"]
60
+ array << gem_name unless alive
50
61
  end
51
62
  end
52
63
 
53
- #
54
- # Saves result to file
55
- #
56
- def save_as_file
57
- body = TomlRB.dump(result.to_h)
58
- File.write(result_file, body)
64
+ def diagnose_by_service(service, urls)
65
+ client = Client::SourceCodeClient.new(service_name: service)
66
+ client.query(urls: urls) do
67
+ announcer.announce
68
+ end
59
69
  end
60
70
 
61
- private
71
+ def result_by_search(collection)
72
+ gems_api_response = gem_client.gems_api_response(collection.names) do
73
+ announcer.announce
74
+ end
62
75
 
63
- attr_reader :lock_file, :result_file, :gem_client, :result
76
+ service_with_urls = gems_api_response.service_with_urls
77
+ error_messages.concat(gems_api_response.error_messages)
64
78
 
65
- def diagnosed_gem?(gem_status)
66
- !gem_status.nil? && !gem_status.unknown?
79
+ result = StatusResult.new
80
+ service_with_urls.each do |service, urls|
81
+ result = result.merge(diagnose_by_service(service, urls))
82
+ end
83
+ result
67
84
  end
68
85
 
69
- def collection_from_file
70
- return @collection_from_file if instance_variable_defined?(:@collection_from_file)
71
-
72
- return GemStatusCollection.new unless File.exist?(result_file)
86
+ def fetch_target_collection(base_collection, gem_names)
87
+ collection = StatusCollection.new
88
+ base_collection.each do |name, status|
89
+ next if gem_names.include?(name)
73
90
 
74
- toml_hash = TomlRB.load_file(result_file)
75
- @collection_from_file = collection_from_hash(toml_hash)
91
+ collection = collection.add(name, status)
92
+ end
93
+ collection
76
94
  end
77
95
 
78
- def collection_from_hash(hash)
79
- hash.each_with_object(GemStatusCollection.new) do |(gem_name, v), collection|
80
- url = v["repository_url"]
81
- next if url.to_sym == GemStatus::REPOSITORY_URL_UNKNOWN
82
-
83
- gem_status = GemStatus.new(name: gem_name,
84
- repository_url: SourceCodeRepositoryUrl.new(url),
85
- alive: v["alive"],
86
- checked_at: v["checked_at"])
87
- collection.add(gem_name, gem_status)
96
+ def collection_from_gemfile
97
+ gems_from_lockfile.each_with_object(StatusCollection.new) do |gem, collection|
98
+ gem_name = gem.name
99
+ status = Status.new(name: gem_name,
100
+ repository_url: nil,
101
+ alive: nil,
102
+ checked_at: nil)
103
+ collection.add(gem_name, status)
88
104
  end
89
105
  end
90
106
 
91
- def gems
92
- lock_file_body = File.read(@lock_file)
93
- lock_file = Bundler::LockfileParser.new(lock_file_body)
94
- lock_file.specs.each
107
+ def _diagnose
108
+ collection = fetch_target_collection(collection_from_gemfile, no_need_to_get_gems)
109
+ result = result_by_search(collection)
110
+ collection_from_toml_file = StatusCollection.new_from_toml_file(result_file)
111
+ new_collection = collection_from_gemfile.merge(collection_from_toml_file)
112
+ .merge(result.collection)
113
+
114
+ messages = error_messages.concat(result.error_messages)
115
+ StatusResult.new(collection: new_collection,
116
+ error_messages: messages,
117
+ rate_limit_exceeded: result.rate_limit_exceeded)
95
118
  end
96
119
 
97
- # rubocop:disable Metrics/MethodLength
98
- def diagnose_gem(gem_name)
99
- gem_status = collection_from_file.get_unchecked(gem_name)
100
- return gem_status if diagnosed_gem?(gem_status)
101
-
102
- unless @rate_limit_exceeded_error
103
- begin
104
- source_code_url = gem_client.get_repository_url(gem_name)
105
- is_alive = SourceCodeRepository.new(url: source_code_url).alive?
106
- rescue Client::SourceCodeClient::RateLimitExceededError => e
107
- @rate_limit_exceeded_error = true
108
- puts e.message
109
- rescue StandardError => e
110
- puts e.message
111
- end
112
- end
113
-
114
- GemStatus.new(name: gem_name,
115
- repository_url: source_code_url,
116
- alive: is_alive,
117
- checked_at: Time.now)
120
+ def gems_from_lockfile
121
+ lock_file_body = File.read(@lock_file)
122
+ lock_file = Bundler::LockfileParser.new(lock_file_body)
123
+ lock_file.specs
118
124
  end
119
- # rubocop:enable Metrics/MethodLength
120
125
  end
121
126
  end
122
127
  end