gem_updater 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/gem_update +13 -0
- data/lib/gem_updater.rb +49 -0
- data/lib/gem_updater/gem_file.rb +34 -0
- data/lib/gem_updater/ruby_gems_fetcher.rb +34 -0
- data/lib/gem_updater/source_page_parser.rb +131 -0
- data/lib/gem_updater_template.erb +5 -0
- metadata +108 -0
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
|
data/lib/gem_updater.rb
ADDED
@@ -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
|
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:
|