gem_updater 2.1.3 → 4.4.0

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: 79fbbd55af8ef3f86354dd4eeb546f5b95de19310313ee24609fc28889c930c9
4
- data.tar.gz: b4bbfb9d8e54e4f3dbcfc4f4343b952c67b0db1536eadeb0541152c4e20e7c15
3
+ metadata.gz: 2a04f3bf2dd4e041cd932e126d162e4a95b7ea2a2a2690a00e97f8a5f62ef6e3
4
+ data.tar.gz: 72af5a2dd171dd37b6281a92c9e6508c6bc6020eb5aa46b218158f4cfcb449ec
5
5
  SHA512:
6
- metadata.gz: 6fd9145c1bc2d8cf431a435305f7cd3c1ddb6bb8a76c23a87e7ed1412504bed7b333d573682ed5a7b814e208bda6b9db21566f9101c795347796be7973728564
7
- data.tar.gz: 137368ce89b4f8ea4f201d339a145b29fae227906721f42ba3a8b8dec242cfb05bef3906bc081699a6626b1e5329219d166732899dbbc1f6fd3245e0377dfb9a
6
+ metadata.gz: 62ccd70ebba5c0d6ea04a47f3cf8e6fd9df7b3c170e09e0af48c238468248e4f241bf17ff6028e31ef078efbf20901869d9c64f6ca64046dd616a9cc5dce94b9
7
+ data.tar.gz: 3e027d0ff378017f0206edab9216eec81d1baa18a8d5b7a6babc287524d917973d8a2127f15df9ea6eb7e00fd575497c10e7b96c20f5c2db233b5140b8054333
@@ -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
@@ -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.open(url).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,19 +55,19 @@ 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
 
60
67
  # Look if gem can be found in another remote
61
68
  #
62
69
  # @return [String|nil] uri of source code
70
+ # rubocop:disable Metrics/MethodLength
63
71
  def uri_from_other_sources
64
72
  uri = nil
65
73
  source.remotes.each do |remote|
@@ -70,34 +78,35 @@ module GemUpdater
70
78
  when 'rails-assets.org'
71
79
  uri_from_railsassets
72
80
  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"
81
+ Bundler.ui.error "Source #{remote} is not supported, ' \
82
+ 'feel free to open a PR or an issue on https://github.com/MaximeD/gem_updater"
74
83
  end
75
84
  end
76
85
 
77
86
  uri
78
87
  end
88
+ # rubocop:enable Metrics/MethodLength
79
89
 
80
90
  # Ask rails-assets.org for source uri of gem.
81
91
  # API is at : https://rails-assets.org/packages/package_name
82
92
  #
83
93
  # @return [String|nil] uri of source code
84
94
  def uri_from_railsassets
85
- if response = query_railsassets
86
- response['url'].gsub(/^git/, 'http')
87
- end
95
+ response = query_railsassets
96
+ return unless response
97
+
98
+ response['url'].gsub(/^git/, 'http')
88
99
  end
89
100
 
90
101
  # Make the real query to railsassets
102
+ # rubocop:disable Lint/SuppressedException
91
103
  def query_railsassets
92
- JSON.parse(
93
- open(
94
- "https://rails-assets.org/packages/#{gem_name.gsub(/rails-assets-/, '')}"
95
- ).read
96
- )
104
+ parse_remote_json("https://rails-assets.org/packages/#{gem_name.gsub(/rails-assets-/, '')}")
97
105
  rescue JSON::ParserError
98
106
  # if gem is not found, rails-assets returns a 200
99
107
  # with html (instead of json) containing a 500...
100
108
  rescue OpenURI::HTTPError
101
109
  end
110
+ # rubocop:enable Lint/SuppressedException
102
111
  end
103
112
  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(uri)))
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
56
  uri = URI(url)
61
-
62
- if uri.scheme == 'http'
63
- known_https(uri)
64
- else
65
- uri
66
- end
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,13 @@ 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]
71
+ when HOSTS[:bitbucket]
81
72
  URI "https://#{uri.host}#{uri.path}"
82
- when uri.host =~ HOSTS[:rubygems]
73
+ when HOSTS[:rubygems]
83
74
  URI "https://#{uri.host}#{uri.path}"
84
75
  else
85
76
  uri
@@ -115,36 +106,42 @@ module GemUpdater
115
106
  MARKUP_FILES.include?(File.extname(file_name))
116
107
  end
117
108
 
109
+ def log_error(error_message)
110
+ Bundler.ui.error error_message
111
+ false
112
+ end
113
+
118
114
  # GitHubParser is responsible for parsing source code
119
115
  # hosted on github.com.
120
116
  class GitHubParser < SourcePageParser
121
- BASE_URL = 'https://github.com'.freeze
117
+ BASE_URL = 'https://github.com'
122
118
 
123
119
  attr_reader :doc, :version
124
120
 
125
121
  # @param doc [Nokogiri::XML::Element] document of source page
126
122
  # @param version [String] version of gem
123
+ # rubocop:disable Lint/MissingSuper
127
124
  def initialize(doc, version)
128
125
  @doc = doc
129
126
  @version = version
130
127
  end
128
+ # rubocop:enable Lint/MissingSuper
131
129
 
132
130
  # Finds url of changelog.
133
131
  #
134
132
  # @return [String] the URL of changelog
135
133
  def changelog
136
134
  url = find_changelog_link
135
+ return unless url
137
136
 
138
- if url
139
- full_url = BASE_URL + url
140
-
141
- if changelog_may_contain_anchor?(full_url)
142
- anchor = find_anchor(full_url)
143
- full_url += anchor if anchor
144
- end
137
+ full_url = BASE_URL + url
145
138
 
146
- full_url
139
+ if changelog_may_contain_anchor?(full_url)
140
+ anchor = find_anchor(full_url)
141
+ full_url += anchor if anchor
147
142
  end
143
+
144
+ full_url
148
145
  end
149
146
 
150
147
  private
@@ -154,7 +151,7 @@ module GemUpdater
154
151
  # @return [String, nil] url of changelog
155
152
  def find_changelog_link
156
153
  changelog_names.find do |name|
157
- node = doc.at_css(%(table.files .content a[title^="#{name}"]))
154
+ node = doc.at_css(%([aria-labelledby="files"] a[title^="#{name}"]))
158
155
 
159
156
  break node.attr('href') if node
160
157
  end
@@ -165,12 +162,12 @@ module GemUpdater
165
162
  # @param url [String] url of changelog
166
163
  # @return [String, nil] anchor's href
167
164
  def find_anchor(url)
168
- changelog_page = Nokogiri::HTML(open(url))
165
+ changelog_page = Nokogiri::HTML(URI.open(url))
169
166
  anchor = changelog_page.css(%(a.anchor)).find do |element|
170
167
  element.attr('href').match(version.delete('.'))
171
168
  end
172
169
 
173
- anchor.attr('href') if anchor
170
+ anchor&.attr('href')
174
171
  end
175
172
  end
176
173
  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: 2.1.3
4
+ version: 4.4.0
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: 2017-11-19 00:00:00.000000000 Z
11
+ date: 2021-01-17 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
@@ -66,9 +80,65 @@ dependencies:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '3.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.78'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.78'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-performance
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.5.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.5.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: vcr
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '6.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '6.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.8'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.8'
69
139
  description: Updates the gems of your Gemfile and fetches the links pointing to where
70
140
  their changelogs are
71
- email: akbarova.armia@gmail.com
141
+ email: maxime_dev@demol.in
72
142
  executables:
73
143
  - gem_update
74
144
  extensions: []
@@ -84,7 +154,7 @@ homepage: https://github.com/MaximeD/gem_updater
84
154
  licenses:
85
155
  - MIT
86
156
  metadata: {}
87
- post_install_message:
157
+ post_install_message:
88
158
  rdoc_options: []
89
159
  require_paths:
90
160
  - lib
@@ -92,16 +162,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
92
162
  requirements:
93
163
  - - ">="
94
164
  - !ruby/object:Gem::Version
95
- version: 2.1.0
165
+ version: 2.5.0
96
166
  required_rubygems_version: !ruby/object:Gem::Requirement
97
167
  requirements:
98
168
  - - ">="
99
169
  - !ruby/object:Gem::Version
100
170
  version: '0'
101
171
  requirements: []
102
- rubyforge_project:
103
- rubygems_version: 2.7.1
104
- signing_key:
172
+ rubygems_version: 3.2.3
173
+ signing_key:
105
174
  specification_version: 4
106
175
  summary: Update your gems and find their changelogs
107
176
  test_files: []