gem_updater 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1b964766638c2f8ef6afc1b87b3d17ae68fec20c
4
+ data.tar.gz: 92e434d50c4d81fb9d95537afe89001fdd9536ea
5
+ SHA512:
6
+ metadata.gz: 04b7c13adf8c38658fb0a47e6df184373f826d94c5bc29f889bd86d85b942cf96506eb6d58d05b41fdf4a5f1d3f457fa2ff3d4cda224080697e5bf5939b6f92b
7
+ data.tar.gz: f01e1bc74d5618300f0728d0e2ed7bf43a8244d27beaedf12b34b4943bf061f3eada7f856ccbc31d15da5e37228d4ae493d95fe0165b31aa088f9f4a57ee32d7
data/bin/gem_update ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Exit cleanly from an early interrupt
4
+ Signal.trap("INT") { exit 1 }
5
+
6
+ require 'gem_updater'
7
+
8
+ gems = GemUpdater::Updater.new
9
+ gems.update!
10
+
11
+ puts "\nHere are your changes:"
12
+ puts '------------------------'
13
+ gems.format_diff
@@ -0,0 +1,49 @@
1
+ require 'gem_updater/gem_file'
2
+ require 'gem_updater/ruby_gems_fetcher'
3
+ require 'gem_updater/source_page_parser'
4
+
5
+ module GemUpdater
6
+ class Updater
7
+
8
+ def initialize
9
+ @gemfile = GemUpdater::GemFile.new
10
+ end
11
+
12
+ # Update process.
13
+ # This will:
14
+ # 1. update gemfile
15
+ # 2. find changelogs for updated gems
16
+ def update!
17
+ @gemfile.update!
18
+
19
+ @gemfile.changes.each do |gem_name, details|
20
+ source_uri = GemUpdater::RubyGemsFetcher.new( gem_name ).source_uri
21
+ source_page = GemUpdater::SourcePageParser.new( url: source_uri, version: details[ :versions ][ :new ] )
22
+
23
+ @gemfile.changes[ gem_name ][ :changelog ] = source_page.changelog if source_page.changelog
24
+ end
25
+ end
26
+
27
+ # Format the diff to get human readable information
28
+ # on the gems that were updated.
29
+ def format_diff
30
+ @gemfile.changes.each do |gem, details|
31
+ puts ERB.new( template, nil, '<>' ).result( binding )
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # Get the template for gem's diff.
38
+ # It can use a custom template.
39
+ #
40
+ # @return [ERB] the template
41
+ def template
42
+ @template ||= begin
43
+ File.read( "#{Dir.home}/.gem_updater_template.erb" )
44
+ rescue Errno::ENOENT
45
+ File.read( File.expand_path( '../../lib/gem_updater_template.erb', __FILE__ ) )
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ require 'bundler/cli'
2
+
3
+ module GemUpdater
4
+
5
+ # GemFile is responsible for handling `Gemfile`
6
+ class GemFile
7
+ attr_accessor :changes
8
+
9
+ def initialize
10
+ @old_spec_set = Bundler.definition.specs
11
+ @changes = {}
12
+ end
13
+
14
+ # Run `bundle update` to update gems.
15
+ # Then get new spec set.
16
+ def update!
17
+ puts "Updating gems..."
18
+ Bundler::CLI.new.update
19
+ @new_spec_set = Bundler.definition.specs
20
+ compute_changes
21
+ end
22
+
23
+ # Compute the diffs between two `Gemfile.lock`.
24
+ #
25
+ # @return [Hash] gems for which there are differences.
26
+ def compute_changes
27
+ @old_spec_set.each do |gem_specs|
28
+ unless ( old_version = gem_specs.version ) == ( new_version = @new_spec_set[ gem_specs.name ].first.version )
29
+ @changes[ gem_specs.name ] = { versions: { old: old_version.to_s, new: new_version.to_s } }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ require 'json'
2
+ require 'nokogiri'
3
+ require 'open-uri'
4
+
5
+ module GemUpdater
6
+
7
+ # RubyGemsFetcher is a wrapper around rubygems API.
8
+ class RubyGemsFetcher
9
+
10
+ # @param gem_name [String] name of the gem
11
+ def initialize( gem_name )
12
+ @gem_name = gem_name
13
+ end
14
+
15
+ # Finds where code is hosted.
16
+ # Most likely in will be in 'source_code_uri' or 'homepage_uri'
17
+ #
18
+ # @return [String] url of gem source code
19
+ def source_uri
20
+ information[ "source_code_uri" ] || information[ "homepage_uri" ]
21
+ end
22
+
23
+ private
24
+
25
+ # Obtain information about a given gem
26
+ # from rubygems.org.
27
+ # See API: http://guides.rubygems.org/rubygems-org-api/#gem-methods
28
+ #
29
+ # @return [Hash] parse of json information
30
+ def information
31
+ @information ||= JSON.parse( open( "https://rubygems.org/api/v1/gems/#{@gem_name}.json" ).read )
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,131 @@
1
+ require 'nokogiri'
2
+ require 'open-uri'
3
+
4
+ module GemUpdater
5
+
6
+ # SourcePageParser is responsible for parsing a source page where
7
+ # the gem code is hosted.
8
+ class SourcePageParser
9
+
10
+ # @param url [String] url of page
11
+ # @param version [String] version of gem
12
+ def initialize( url: nil, version: nil )
13
+ @uri = correct_uri( url )
14
+ @version = version
15
+ end
16
+
17
+ # Get the changelog in an uri.
18
+ #
19
+ # @return [String, nil] URL of changelog
20
+ def changelog
21
+ @changelog ||= begin
22
+ puts "Looking for a changelog in #{@uri}"
23
+ doc = Nokogiri::HTML( open( @uri ) )
24
+
25
+ find_changelog( doc )
26
+
27
+ rescue OpenURI::HTTPError # Uri points to nothing
28
+ puts "Cannot find #{@uri}"
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # Some gems have 'http://github.com' as URI which will redirect to https
35
+ # leading `open_uri` to crash.
36
+ #
37
+ # @param url [String] the url to parse
38
+ # @return [URI] valid URI
39
+ def correct_uri( url )
40
+ uri = URI( url )
41
+ uri.scheme = 'https' if uri.host == 'github.com' && uri.scheme == 'http'
42
+
43
+ uri
44
+ end
45
+
46
+ # Try to find where changelog might be.
47
+ #
48
+ # @param doc [Nokogiri::XML::Element] document of source page
49
+ def find_changelog( doc )
50
+ case @uri.host
51
+ when 'github.com'
52
+ GitHubParser.new( doc, @version ).changelog
53
+ end
54
+ end
55
+
56
+ # List possible names for a changelog
57
+ # since humans may have many many ways to call it.
58
+ #
59
+ # @return [Array] list of possible names
60
+ def changelog_names
61
+ %w( CHANGELOG Changelog ChangeLog changelog HISTORY History history )
62
+ end
63
+
64
+ # Some documents like the one written in markdown may contain
65
+ # a direct anchor to specific version.
66
+ #
67
+ # @param file_name [String] file name of changelog
68
+ # @return [Boolean] true if file may contain an anchor
69
+ def changelog_may_contain_anchor?( file_name )
70
+ %w( .md .rdoc ).include?( File.extname( file_name ) )
71
+ end
72
+
73
+ # GitHubParser is responsible for parsing source code
74
+ # hosted on github.com.
75
+ class GitHubParser < SourcePageParser
76
+ BASE_URL = 'https://github.com'
77
+
78
+ # @param doc [Nokogiri::XML::Element] document of source page
79
+ # @param version [String] version of gem
80
+ def initialize( doc, version )
81
+ @doc = doc
82
+ @version = version
83
+ end
84
+
85
+ # Finds url of changelog.
86
+ #
87
+ # @return [String] the URL of changelog
88
+ def changelog
89
+ url = find_changelog_link
90
+
91
+ if url
92
+ full_url = BASE_URL + url
93
+
94
+ if changelog_may_contain_anchor?( full_url )
95
+ anchor = find_anchor( full_url )
96
+ full_url += anchor if anchor
97
+ end
98
+
99
+ full_url
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ # Find which link corresponds to changelog.
106
+ #
107
+ # @return [String, nil] url of changelog
108
+ def find_changelog_link
109
+ changelog_names.find do |name|
110
+ node = @doc.at_css( %(table.files a[title^="#{name}"]) )
111
+ if node
112
+ break node.attr( 'href' )
113
+ end
114
+ end
115
+ end
116
+
117
+ # Looks into document to find it there is an anchor to new gem version.
118
+ #
119
+ # @param url [String] url of changelog
120
+ # @return [String, nil] anchor's href
121
+ def find_anchor( url )
122
+ changelog_page = Nokogiri::HTML( open( url ) )
123
+ anchor = changelog_page.css( %(a.anchor) ).find{ |element| element.attr( 'href' ).match( @version.gsub('.', '') ) }
124
+
125
+ if anchor
126
+ anchor.attr( 'href' )
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,5 @@
1
+ * <%= gem %> <%= details[ :versions ][ :old ] %> → <%= details[ :versions ][ :new ] %>
2
+ <% if details[ :changelog ] %>
3
+ [changelog](<%= details[ :changelog ] %>)
4
+ <% end %>
5
+
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gem_updater
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Maxime Demolin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: It updates the gems of your Gemfile and fetches the links pointing to
70
+ where their changelogs are
71
+ email: akbarova.armia@gmail.com
72
+ executables:
73
+ - gem_update
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - bin/gem_update
78
+ - lib/gem_updater.rb
79
+ - lib/gem_updater/gem_file.rb
80
+ - lib/gem_updater/ruby_gems_fetcher.rb
81
+ - lib/gem_updater/source_page_parser.rb
82
+ - lib/gem_updater_template.erb
83
+ homepage: https://github.com/MaximeD/gem_updater
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 2.4.5
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Update your gems and find their changelogs
107
+ test_files: []
108
+ has_rdoc: