gem_updater 3.0.0 → 4.4.1

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: 458c286b02adc73fdeac3eded5de4b65390c1bfa0374efc83651b773f96f2f7b
4
- data.tar.gz: bf55e5150ee714581df3b41e4177878c2b432d44c369d8bdd1cf62ae8f435d21
3
+ metadata.gz: 10e740d324e4bd91b5e7b8d6c7d2c4272b84eedf0cabcab2e5244c55779a4a2c
4
+ data.tar.gz: d7050c27a7791a3b185c08e088e29c9cf645908106d352027d3ddb02f826bdae
5
5
  SHA512:
6
- metadata.gz: be83c20442e904d34c99f3674532ac80ff891e7a088abfe7f9d7867bad4c2208066ac57fd6861c508d3d47624a0f7946f72e48cb8d99abe4272e6aa3e7554287
7
- data.tar.gz: 769a8fcbbe5b19d9e9c334079e5c3a84c1fbf0d4688aace73ee33b808ee8d4fd3728247b617985694b80365715a3787768b3a24a5d9ba10c811e8bf1b0b4f692
6
+ metadata.gz: 26be9e96400f04d892de240c28af03f02d5e5d23ec33d51bdbce015883df6bc4de2a1631da3ab42b1bada40384868a095f1b1e2c1a82fe1f6ca7cbd231656864
7
+ data.tar.gz: 55a53a16a210ef6380ca2bc3febafaf01ecd42de0693fa88fcabfe7302e195d9fe0ba69989bcc37b9638f085cb06a42fe33a3c78e1e691bb4557f291b043e90a
data/bin/gem_update CHANGED
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
2
5
  require 'optparse'
3
6
 
4
7
  # Exit cleanly from an early interrupt
5
8
  Signal.trap('INT') { exit 1 }
6
9
 
7
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
10
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
8
11
  require 'gem_updater'
9
12
 
10
13
  Bundler.ui = Bundler::UI::Shell.new
data/lib/gem_updater.rb CHANGED
@@ -1,12 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+ require 'memoist'
1
5
  require 'gem_updater/gem_file'
2
6
  require 'gem_updater/ruby_gems_fetcher'
3
7
  require 'gem_updater/source_page_parser'
4
8
 
9
+ # Base lib.
5
10
  module GemUpdater
6
-
7
11
  # Updater's main responsability is to fill changes
8
12
  # happened before and after update of `Gemfile`, and then format them.
9
13
  class Updater
14
+ extend Memoist
15
+
10
16
  attr_accessor :gemfile
11
17
 
12
18
  def initialize
@@ -43,23 +49,11 @@ module GemUpdater
43
49
 
44
50
  # For each gem, retrieve its changelog
45
51
  def fill_changelogs
46
- threads = []
47
-
48
- gemfile.changes.each do |gem_name, details|
49
- threads << Thread.new do
50
- if source_uri = find_source(gem_name, details[:source])
51
- source_page = GemUpdater::SourcePageParser.new(
52
- url: source_uri, version: details[:versions][:new]
53
- )
54
-
55
- if source_page.changelog
56
- gemfile.changes[gem_name][:changelog] = source_page.changelog
57
- end
58
- end
52
+ [].tap do |threads|
53
+ gemfile.changes.each do |gem_name, details|
54
+ threads << Thread.new { retrieve_gem_changes(gem_name, details) }
59
55
  end
60
- end
61
-
62
- threads.each(&:join)
56
+ end.each(&:join)
63
57
  end
64
58
 
65
59
  # Find where is hosted the source of a gem
@@ -76,16 +70,26 @@ module GemUpdater
76
70
  end
77
71
  end
78
72
 
73
+ def retrieve_gem_changes(gem_name, details)
74
+ source_uri = find_source(gem_name, details[:source])
75
+ return unless source_uri
76
+
77
+ source_page = GemUpdater::SourcePageParser.new(
78
+ url: source_uri, version: details[:versions][:new]
79
+ )
80
+
81
+ gemfile.changes[gem_name][:changelog] = source_page.changelog if source_page.changelog
82
+ end
83
+
79
84
  # Get the template for gem's diff.
80
85
  # It can use a custom template.
81
86
  #
82
87
  # @return [ERB] the template
83
88
  def template
84
- @template ||= begin
85
- File.read("#{Dir.home}/.gem_updater_template.erb")
86
- rescue Errno::ENOENT
87
- File.read(File.expand_path('../../lib/gem_updater_template.erb', __FILE__))
88
- end
89
+ File.read("#{Dir.home}/.gem_updater_template.erb")
90
+ rescue Errno::ENOENT
91
+ File.read(File.expand_path('../lib/gem_updater_template.erb', __dir__))
89
92
  end
93
+ memoize :template
90
94
  end
91
95
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler'
1
4
  require 'bundler/cli'
2
5
 
3
6
  module GemUpdater
4
-
5
7
  # GemFile is responsible for handling `Gemfile`
6
8
  class GemFile
7
9
  attr_accessor :changes
@@ -21,21 +23,20 @@ module GemUpdater
21
23
  #
22
24
  # @return [Hash] gems for which there are differences.
23
25
  def compute_changes
24
- get_spec_sets
26
+ spec_sets_diff!
25
27
 
26
28
  old_spec_set.each do |old_gem|
27
29
  updated_gem = new_spec_set.find { |new_gem| new_gem.name == old_gem.name }
30
+ next unless updated_gem && old_gem.version != updated_gem.version
28
31
 
29
- if updated_gem && old_gem.version != updated_gem.version
30
- fill_changes(old_gem, updated_gem)
31
- end
32
+ fill_changes(old_gem, updated_gem)
32
33
  end
33
34
  end
34
35
 
35
36
  private
36
37
 
37
38
  # Get the two spec sets (before and after `bundle update`)
38
- def get_spec_sets
39
+ def spec_sets_diff!
39
40
  @old_spec_set = spec_set
40
41
  reinitialize_spec_set!
41
42
  @new_spec_set = spec_set
@@ -1,12 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
  require 'nokogiri'
3
5
  require 'open-uri'
4
6
 
5
7
  module GemUpdater
6
-
7
8
  # RubyGemsFetcher is a wrapper around rubygems API.
8
9
  class RubyGemsFetcher
9
- HTTP_TOO_MANY_REQUESTS = '429'.freeze
10
+ HTTP_TOO_MANY_REQUESTS = '429'
10
11
  GEM_HOMEPAGES = %w[source_code_uri homepage_uri].freeze
11
12
 
12
13
  attr_reader :gem_name, :source
@@ -28,6 +29,14 @@ module GemUpdater
28
29
 
29
30
  private
30
31
 
32
+ # Parse JSON from a remote url.
33
+ #
34
+ # @param url [String] remote url
35
+ # @return [Hash] parsed JSON
36
+ def parse_remote_json(url)
37
+ JSON.parse(URI.parse(url).open.read)
38
+ end
39
+
31
40
  # Ask rubygems.org for source uri of gem.
32
41
  # See API: http://guides.rubygems.org/rubygems-org-api/#gem-methods
33
42
  #
@@ -35,11 +44,10 @@ module GemUpdater
35
44
  def uri_from_rubygems
36
45
  return unless source.remotes.map(&:host).include?('rubygems.org')
37
46
 
38
- if response = query_rubygems
39
- response[
40
- GEM_HOMEPAGES.find { |key| response[key] && !response[key].empty? }
41
- ]
42
- end
47
+ response = query_rubygems
48
+ return unless response
49
+
50
+ response[GEM_HOMEPAGES.find { |key| response[key] && !response[key].empty? }]
43
51
  end
44
52
 
45
53
  # Make the real query to rubygems
@@ -47,13 +55,12 @@ module GemUpdater
47
55
  #
48
56
  # @param tries [Integer|nil] (optional) how many times we tried
49
57
  def query_rubygems(tries = 0)
50
- JSON.parse(open("https://rubygems.org/api/v1/gems/#{gem_name}.json").read)
58
+ parse_remote_json("https://rubygems.org/api/v1/gems/#{gem_name}.json")
51
59
  rescue OpenURI::HTTPError => e
52
60
  # We may trigger too many requests, in which case give rubygems a break
53
61
  if e.io.status.include?(HTTP_TOO_MANY_REQUESTS)
54
- if (tries += 1) < 2
55
- sleep 1 and retry
56
- end
62
+ tries += 1
63
+ sleep 1 && retry if tries < 2
57
64
  end
58
65
  end
59
66
 
@@ -61,20 +68,16 @@ module GemUpdater
61
68
  #
62
69
  # @return [String|nil] uri of source code
63
70
  def uri_from_other_sources
64
- uri = nil
65
- source.remotes.each do |remote|
66
- break if uri
67
-
68
- uri = case remote.host
69
- when 'rubygems.org' then next # already checked
70
- when 'rails-assets.org'
71
- uri_from_railsassets
72
- else
73
- Bundler.ui.error "Source #{remote} is not supported, feel free to open a PR or an issue on https://github.com/MaximeD/gem_updater"
74
- end
71
+ source.remotes.find do |remote|
72
+ case remote.host
73
+ when 'rubygems.org' then next # already checked
74
+ when 'rails-assets.org'
75
+ return uri_from_railsassets
76
+ else
77
+ Bundler.ui.error "Source #{remote} is not supported, ' \
78
+ 'feel free to open a PR or an issue on https://github.com/MaximeD/gem_updater"
79
+ end
75
80
  end
76
-
77
- uri
78
81
  end
79
82
 
80
83
  # Ask rails-assets.org for source uri of gem.
@@ -82,22 +85,21 @@ module GemUpdater
82
85
  #
83
86
  # @return [String|nil] uri of source code
84
87
  def uri_from_railsassets
85
- if response = query_railsassets
86
- response['url'].gsub(/^git/, 'http')
87
- end
88
+ response = query_railsassets
89
+ return unless response
90
+
91
+ response['url'].gsub(/^git/, 'http')
88
92
  end
89
93
 
90
94
  # Make the real query to railsassets
95
+ # rubocop:disable Lint/SuppressedException
91
96
  def query_railsassets
92
- JSON.parse(
93
- open(
94
- "https://rails-assets.org/packages/#{gem_name.gsub(/rails-assets-/, '')}"
95
- ).read
96
- )
97
+ parse_remote_json("https://rails-assets.org/packages/#{gem_name.gsub(/rails-assets-/, '')}")
97
98
  rescue JSON::ParserError
98
99
  # if gem is not found, rails-assets returns a 200
99
100
  # with html (instead of json) containing a 500...
100
101
  rescue OpenURI::HTTPError
101
102
  end
103
+ # rubocop:enable Lint/SuppressedException
102
104
  end
103
105
  end
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nokogiri'
2
4
  require 'open-uri'
3
5
 
4
6
  module GemUpdater
5
-
6
7
  # SourcePageParser is responsible for parsing a source page where
7
8
  # the gem code is hosted.
8
9
  class SourcePageParser
10
+ extend Memoist
11
+
9
12
  HOSTS = {
10
13
  github: /github.com/,
11
14
  bitbucket: /bitbucket.org/,
@@ -29,23 +32,16 @@ module GemUpdater
29
32
  def changelog
30
33
  return unless uri
31
34
 
32
- @changelog ||= begin
33
- Bundler.ui.warn "Looking for a changelog in #{uri}"
34
- doc = Nokogiri::HTML(open(uri))
35
-
36
- find_changelog(doc)
37
-
38
- rescue OpenURI::HTTPError # Uri points to nothing
39
- Bundler.ui.error "Cannot find #{uri}"
40
- false
41
- rescue Errno::ETIMEDOUT # timeout
42
- Bundler.ui.error "#{uri} is down"
43
- false
44
- rescue ArgumentError => e # x-oauth-basic raises userinfo not supported. [RFC3986]
45
- Bundler.ui.error e
46
- false
47
- end
35
+ Bundler.ui.warn "Looking for a changelog in #{uri}"
36
+ find_changelog(Nokogiri::HTML(uri.open))
37
+ rescue OpenURI::HTTPError # Uri points to nothing
38
+ log_error("Cannot find #{uri}")
39
+ rescue Errno::ETIMEDOUT # timeout
40
+ log_error("#{uri} is down")
41
+ rescue ArgumentError => e # x-oauth-basic raises userinfo not supported. [RFC3986]
42
+ log_error(e)
48
43
  end
44
+ memoize :changelog
49
45
 
50
46
  private
51
47
 
@@ -55,15 +51,10 @@ module GemUpdater
55
51
  # @param url [String] the url to parse
56
52
  # @return [URI] valid URI
57
53
  def correct_uri(url)
58
- return unless String === url && !url.empty?
54
+ return unless url.is_a?(String) && !url.empty?
59
55
 
60
- uri = URI(url)
61
-
62
- if uri.scheme == 'http'
63
- known_https(uri)
64
- else
65
- uri
66
- end
56
+ uri = URI.parse(url)
57
+ uri.scheme == 'http' ? known_https(uri) : uri
67
58
  end
68
59
 
69
60
  # Some uris are not https, but we know they should be,
@@ -73,13 +64,11 @@ module GemUpdater
73
64
  # @param uri [URI::HTTP]
74
65
  # @return [URI::HTTPS|URI::HTTP]
75
66
  def known_https(uri)
76
- case
77
- when uri.host =~ HOSTS[:github]
67
+ case uri.host
68
+ when HOSTS[:github]
78
69
  # remove possible subdomain like 'wiki.github.com'
79
70
  URI "https://github.com#{uri.path}"
80
- when uri.host =~ HOSTS[:bitbucket]
81
- URI "https://#{uri.host}#{uri.path}"
82
- when uri.host =~ HOSTS[:rubygems]
71
+ when HOSTS[:bitbucket], HOSTS[:rubygems]
83
72
  URI "https://#{uri.host}#{uri.path}"
84
73
  else
85
74
  uri
@@ -115,49 +104,55 @@ module GemUpdater
115
104
  MARKUP_FILES.include?(File.extname(file_name))
116
105
  end
117
106
 
107
+ def log_error(error_message)
108
+ Bundler.ui.error error_message
109
+ false
110
+ end
111
+
118
112
  # GitHubParser is responsible for parsing source code
119
113
  # hosted on github.com.
120
114
  class GitHubParser < SourcePageParser
121
- BASE_URL = 'https://github.com'.freeze
115
+ BASE_URL = 'https://github.com'
122
116
 
123
117
  attr_reader :doc, :version
124
118
 
125
119
  # @param doc [Nokogiri::XML::Element] document of source page
126
120
  # @param version [String] version of gem
121
+ # rubocop:disable Lint/MissingSuper
127
122
  def initialize(doc, version)
128
123
  @doc = doc
129
124
  @version = version
130
125
  end
126
+ # rubocop:enable Lint/MissingSuper
131
127
 
132
128
  # Finds url of changelog.
133
129
  #
134
130
  # @return [String] the URL of changelog
135
131
  def changelog
136
132
  url = find_changelog_link
133
+ return unless url
137
134
 
138
- if url
139
- full_url = BASE_URL + url
135
+ full_url = BASE_URL + url
140
136
 
141
- if changelog_may_contain_anchor?(full_url)
142
- anchor = find_anchor(full_url)
143
- full_url += anchor if anchor
144
- end
145
-
146
- full_url
137
+ if changelog_may_contain_anchor?(full_url)
138
+ anchor = find_anchor(full_url)
139
+ full_url += anchor if anchor
147
140
  end
141
+
142
+ full_url
148
143
  end
149
144
 
150
145
  private
151
146
 
152
147
  # Find which link corresponds to changelog.
148
+ # Last one is taken as files come after directories. So if there is a directory plus a file
149
+ # matching a changelog name, we ensure file is preferred.
153
150
  #
154
151
  # @return [String, nil] url of changelog
155
152
  def find_changelog_link
156
- changelog_names.find do |name|
157
- node = doc.at_css(%(table.files .content a[title^="#{name}"]))
158
-
159
- break node.attr('href') if node
160
- end
153
+ changelog_names.map do |name|
154
+ doc.at_css(%([aria-labelledby="files"] a[title^="#{name}"]))
155
+ end.compact.last&.attr('href')
161
156
  end
162
157
 
163
158
  # Looks into document to find it there is an anchor to new gem version.
@@ -165,12 +160,12 @@ module GemUpdater
165
160
  # @param url [String] url of changelog
166
161
  # @return [String, nil] anchor's href
167
162
  def find_anchor(url)
168
- changelog_page = Nokogiri::HTML(open(url))
163
+ changelog_page = Nokogiri::HTML(URI.parse(url).open)
169
164
  anchor = changelog_page.css(%(a.anchor)).find do |element|
170
165
  element.attr('href').match(version.delete('.'))
171
166
  end
172
167
 
173
- anchor.attr('href') if anchor
168
+ anchor&.attr('href')
174
169
  end
175
170
  end
176
171
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem_updater
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 4.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxime Demolin
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-10 00:00:00.000000000 Z
11
+ date: 2021-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - "<"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.16'
19
+ version: '3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - "<"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.16'
26
+ version: '3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: json
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: memoist
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.16.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.16.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: nokogiri
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '1.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.14'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.14'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rspec
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -66,9 +94,65 @@ dependencies:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
96
  version: '3.7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-performance
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.5.2
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.5.2
125
+ - !ruby/object:Gem::Dependency
126
+ name: vcr
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '6.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '6.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: webmock
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.8'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '3.8'
69
153
  description: Updates the gems of your Gemfile and fetches the links pointing to where
70
154
  their changelogs are
71
- email: akbarova.armia@gmail.com
155
+ email: maxime_dev@demol.in
72
156
  executables:
73
157
  - gem_update
74
158
  extensions: []
@@ -84,7 +168,7 @@ homepage: https://github.com/MaximeD/gem_updater
84
168
  licenses:
85
169
  - MIT
86
170
  metadata: {}
87
- post_install_message:
171
+ post_install_message:
88
172
  rdoc_options: []
89
173
  require_paths:
90
174
  - lib
@@ -92,16 +176,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
92
176
  requirements:
93
177
  - - ">="
94
178
  - !ruby/object:Gem::Version
95
- version: 2.3.0
179
+ version: 2.5.0
96
180
  required_rubygems_version: !ruby/object:Gem::Requirement
97
181
  requirements:
98
182
  - - ">="
99
183
  - !ruby/object:Gem::Version
100
184
  version: '0'
101
185
  requirements: []
102
- rubyforge_project:
103
- rubygems_version: 2.7.6
104
- signing_key:
186
+ rubygems_version: 3.2.3
187
+ signing_key:
105
188
  specification_version: 4
106
189
  summary: Update your gems and find their changelogs
107
190
  test_files: []