gem_updater 2.1.3 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
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: []