travis_check_rubies 0.2.5 → 0.6.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 +5 -5
- data/.travis.yml +9 -15
- data/LICENSE.txt +1 -1
- data/README.markdown +1 -1
- data/bin/travis_check_rubies +14 -2
- data/lib/travis_check_rubies.rb +1 -1
- data/lib/travis_check_rubies/fetcher.rb +44 -0
- data/lib/travis_check_rubies/rvm_index.rb +11 -0
- data/lib/travis_check_rubies/travis_index.rb +45 -0
- data/lib/travis_check_rubies/travis_yml.rb +126 -35
- data/lib/travis_check_rubies/updater.rb +98 -0
- data/lib/travis_check_rubies/version.rb +6 -56
- data/spec/travis_check_rubies/fetcher_spec.rb +48 -0
- data/spec/travis_check_rubies/travis_index_spec.rb +31 -0
- data/spec/travis_check_rubies/updater_spec.rb +116 -0
- data/spec/travis_check_rubies/version_spec.rb +4 -114
- data/travis_check_rubies.gemspec +10 -3
- metadata +37 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 754293bfea3d3b93d0cca432c90b7b792ff7cf5634a670f8cdd8f82e4d3511b6
|
4
|
+
data.tar.gz: af8d4c0090e245130ac90dad26bd6068e08d340fe1c2a52f73352d3b0e15d1a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73413645cbabaeea6f125258ad0df781e10f7dd2df886fdde4aac740cdd5651fa4bea375fb9860274a75b6a4100bd385ca1df3c3bd70ab7cab162c86b4e45cff
|
7
|
+
data.tar.gz: 026aec14d310b2b61bba7c34787c7159c6a11acc403af9cb4602f2d83b0559f03806ff7ad8ee97223315189cf9e3ee9b7223309ede98daf7f7b7df3fa96e7e04
|
data/.travis.yml
CHANGED
@@ -1,23 +1,17 @@
|
|
1
|
-
|
1
|
+
dist: xenial
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
- '2.
|
5
|
-
- '2.
|
6
|
-
- '2.
|
7
|
-
- '2.
|
8
|
-
- '2.
|
9
|
-
- '
|
10
|
-
- 'jruby-9.1.
|
4
|
+
- '2.3.8'
|
5
|
+
- '2.4.10'
|
6
|
+
- '2.5.9'
|
7
|
+
- '2.6.7'
|
8
|
+
- '2.7.3'
|
9
|
+
- '3.0.1'
|
10
|
+
- 'jruby-9.1.17.0'
|
11
|
+
- 'jruby-9.2.14.0'
|
11
12
|
before_script:
|
12
13
|
- env
|
13
14
|
- rvm debug
|
14
15
|
script:
|
15
16
|
- bundle exec rspec
|
16
17
|
- bundle exec travis_check_rubies
|
17
|
-
matrix:
|
18
|
-
allow_failures:
|
19
|
-
- rvm: 'jruby-9.0.5.0'
|
20
|
-
exclude:
|
21
|
-
- rvm: 'jruby-9.0.5.0'
|
22
|
-
include:
|
23
|
-
- rvm: 'jruby-9.0.5.0'
|
data/LICENSE.txt
CHANGED
data/README.markdown
CHANGED
data/bin/travis_check_rubies
CHANGED
@@ -6,6 +6,8 @@ require 'yaml'
|
|
6
6
|
|
7
7
|
CONFIG_FILE = '.travis_check_rubies.yml'
|
8
8
|
|
9
|
+
update = false
|
10
|
+
|
9
11
|
options = if File.exist?(CONFIG_FILE)
|
10
12
|
yaml = YAML.load_file(CONFIG_FILE) || {}
|
11
13
|
fail "#{CONFIG_FILE} doesn't contain options hash" unless yaml.is_a?(Hash)
|
@@ -36,11 +38,21 @@ end
|
|
36
38
|
op.on('--exclude V,V,V', Array, 'Exclude matching versions') do |exclude|
|
37
39
|
options[:exclude] = exclude
|
38
40
|
end
|
41
|
+
op.on('--conservative', 'Update to first instead of last possible version') do
|
42
|
+
options[:conservative] = true
|
43
|
+
end
|
44
|
+
op.on('-u', '--update', 'Update versions') do
|
45
|
+
update = true
|
46
|
+
end
|
39
47
|
begin
|
40
48
|
op.parse!
|
41
49
|
rescue => e
|
42
50
|
abort "#{e}\n\n#{op.help}"
|
43
51
|
end
|
44
52
|
|
45
|
-
|
46
|
-
|
53
|
+
travis_yml = TravisCheckRubies::TravisYml.new(options: options)
|
54
|
+
if update
|
55
|
+
abort unless travis_yml.update
|
56
|
+
else
|
57
|
+
abort unless travis_yml.suggest
|
58
|
+
end
|
data/lib/travis_check_rubies.rb
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'fspath'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module TravisCheckRubies
|
7
|
+
class Fetcher
|
8
|
+
CACHE_TIME = 24 * 60 * 60
|
9
|
+
|
10
|
+
attr_reader :url
|
11
|
+
|
12
|
+
def initialize(url)
|
13
|
+
@url = url
|
14
|
+
end
|
15
|
+
|
16
|
+
def data
|
17
|
+
cached_data || fetch_data
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def cache_path
|
23
|
+
@cache_path ||= FSPath(ENV['XDG_CACHE_HOME'] || '~/.cache').expand_path / "travis_check_rubies.#{Digest::SHA1.hexdigest url}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def cached_data
|
27
|
+
return unless cache_path.size?
|
28
|
+
return unless cache_path.mtime + CACHE_TIME > Time.now
|
29
|
+
cache_path.read
|
30
|
+
end
|
31
|
+
|
32
|
+
def fetch_data
|
33
|
+
data = Net::HTTP.get(URI(url))
|
34
|
+
|
35
|
+
cache_path.dirname.mkpath
|
36
|
+
FSPath.temp_file('travis_check_rubies', cache_path.dirname) do |f|
|
37
|
+
f.write(data)
|
38
|
+
f.path.rename(cache_path)
|
39
|
+
end
|
40
|
+
|
41
|
+
data
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'fetcher'
|
2
|
+
|
3
|
+
require 'travis_check_rubies/travis_yml'
|
4
|
+
|
5
|
+
module TravisCheckRubies
|
6
|
+
class TravisIndex
|
7
|
+
ROOT_URL = 'https://rubies.travis-ci.org/'
|
8
|
+
|
9
|
+
LTS_VERSIONS = {
|
10
|
+
precise: '12.04',
|
11
|
+
trusty: '14.04',
|
12
|
+
xenial: '16.04',
|
13
|
+
bionic: '18.04',
|
14
|
+
focal: '20.04',
|
15
|
+
}
|
16
|
+
|
17
|
+
def version_strings
|
18
|
+
$stderr.puts "Using #{base_url}"
|
19
|
+
index_urls.select do |url|
|
20
|
+
url.start_with?(base_url)
|
21
|
+
end.map do |url|
|
22
|
+
url[%r{([^/]+)\.tar\.(?:gz|bz2)$}, 1]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def index_urls
|
29
|
+
@index_urls ||= TravisCheckRubies::Fetcher.new(ROOT_URL + 'index.txt').data.split("\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
def base_url
|
33
|
+
@base_url ||= begin
|
34
|
+
base_ubuntu_url = "#{ROOT_URL}ubuntu/"
|
35
|
+
dist = TravisYml.new.dist
|
36
|
+
version = LTS_VERSIONS[dist.to_sym]
|
37
|
+
if version
|
38
|
+
"#{base_ubuntu_url}#{version}/x86_64/"
|
39
|
+
else
|
40
|
+
fail "Unknown dist #{dist}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,66 +1,157 @@
|
|
1
|
+
require 'fspath'
|
1
2
|
require 'yaml'
|
2
|
-
|
3
|
+
|
4
|
+
require_relative 'updater'
|
5
|
+
require_relative 'version'
|
3
6
|
|
4
7
|
module TravisCheckRubies
|
5
8
|
class TravisYml
|
6
|
-
|
7
|
-
|
9
|
+
Suggestion = Struct.new(:section, :from, :choices, :to)
|
10
|
+
|
11
|
+
attr_reader :path, :options
|
8
12
|
|
9
|
-
def initialize(path
|
10
|
-
@path = path
|
13
|
+
def initialize(path: '.travis.yml', options: {})
|
14
|
+
@path = FSPath(path)
|
15
|
+
@options = options
|
16
|
+
end
|
11
17
|
|
12
|
-
|
13
|
-
|
14
|
-
@allow_failures_versions = matrix_versions(yaml, 'allow_failures')
|
15
|
-
@exclude_versions = matrix_versions(yaml, 'exclude')
|
16
|
-
@include_versions = matrix_versions(yaml, 'include')
|
18
|
+
def dist
|
19
|
+
original_object['dist'] || 'xenial'
|
17
20
|
end
|
18
21
|
|
19
|
-
def
|
20
|
-
|
22
|
+
def warnings
|
23
|
+
return @warnings if @warnings
|
21
24
|
|
22
|
-
|
25
|
+
@warnings = []
|
23
26
|
|
24
|
-
versions.each do |version|
|
25
|
-
|
26
|
-
suggestions['rvm'] << "#{version} -> #{for_version.join(', ')}"
|
27
|
+
rvm_versions.group_by(&:itself).select{ |_, versions| versions.count > 1 }.each do |version, _|
|
28
|
+
@warnings << "#{version} in rvm is repeating"
|
27
29
|
end
|
28
30
|
|
29
|
-
allow_failures_versions.each do |version|
|
30
|
-
|
31
|
-
next if include_versions.include?(version)
|
32
|
-
suggestions['matrix.allow_failures'] << "#{version} in matrix.allow_failures is not in rvm or include list"
|
31
|
+
(allow_failures_versions - rvm_versions - include_versions).each do |version|
|
32
|
+
@warnings << "#{version} in matrix.allow_failures is not in rvm or include list"
|
33
33
|
end
|
34
34
|
|
35
|
-
exclude_versions.each do |version|
|
36
|
-
|
37
|
-
|
35
|
+
(exclude_versions - rvm_versions).each do |version|
|
36
|
+
@warnings << "#{version} in matrix.exclude is not in rvm list"
|
37
|
+
end
|
38
|
+
|
39
|
+
@warnings
|
40
|
+
end
|
41
|
+
|
42
|
+
def suggestions
|
43
|
+
return @suggestions if @suggestions
|
44
|
+
|
45
|
+
@suggestions = []
|
46
|
+
|
47
|
+
updates = Version.updates(rvm_versions, **options)
|
48
|
+
rvm_versions.each do |version|
|
49
|
+
next unless (suggestions = updates[version])
|
50
|
+
@suggestions << Suggestion.new('rvm', version, suggestions)
|
38
51
|
end
|
39
52
|
|
40
53
|
{
|
41
|
-
'
|
42
|
-
'
|
54
|
+
'allow_failures' => allow_failures_versions,
|
55
|
+
'exclude' => exclude_versions,
|
56
|
+
'include' => include_versions,
|
43
57
|
}.each do |section, versions|
|
44
58
|
versions.each do |version|
|
45
|
-
next unless (
|
46
|
-
|
59
|
+
next unless (suggestions = Version.update(version, **options))
|
60
|
+
next if suggestions.include?(version)
|
61
|
+
to = section == 'include' && !options[:conservative] ? suggestions.last : suggestions.first
|
62
|
+
@suggestions << Suggestion.new(section, version, suggestions, to)
|
47
63
|
end
|
48
64
|
end
|
49
65
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
66
|
+
@suggestions
|
67
|
+
end
|
68
|
+
|
69
|
+
def suggest
|
70
|
+
puts warnings
|
71
|
+
|
72
|
+
suggestions.group_by(&:section).each do |section, section_suggestions|
|
73
|
+
puts "#{section}:"
|
74
|
+
section_suggestions.each do |suggestion|
|
75
|
+
puts " #{suggestion.from} -> #{suggestion.choices.join(', ')}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
warnings.empty? && suggestions.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
def update
|
83
|
+
unless warnings.empty?
|
84
|
+
puts warnings
|
85
|
+
|
86
|
+
return false
|
87
|
+
end
|
88
|
+
|
89
|
+
unless YAML.load(updated_content) == expected_object
|
90
|
+
puts updated_content
|
91
|
+
|
92
|
+
return false
|
93
|
+
end
|
94
|
+
|
95
|
+
FSPath.temp_file(path.basename, path.dirname) do |f|
|
96
|
+
f.write(updated_content)
|
97
|
+
f.path.rename(path)
|
54
98
|
end
|
55
99
|
|
56
|
-
|
57
|
-
suggestions.map do |section, lines|
|
58
|
-
"#{section}:\n#{lines.map{ |line| " #{line}" }.join("\n")}"
|
59
|
-
end.join("\n")
|
100
|
+
true
|
60
101
|
end
|
61
102
|
|
62
103
|
private
|
63
104
|
|
105
|
+
def original_content
|
106
|
+
@original_content ||= path.read
|
107
|
+
end
|
108
|
+
|
109
|
+
def original_object
|
110
|
+
@original_object ||= YAML.load(original_content)
|
111
|
+
end
|
112
|
+
|
113
|
+
def expected_object
|
114
|
+
@expected_object ||= YAML.load(original_content).tap do |expected|
|
115
|
+
suggestions.each do |suggestion|
|
116
|
+
if suggestion.section == 'rvm'
|
117
|
+
index = expected['rvm'].find_index{ |v| suggestion.from == v }
|
118
|
+
expected['rvm'][index, 1] = suggestion.choices.map(&:to_s)
|
119
|
+
else
|
120
|
+
entry = expected['matrix'][suggestion.section].find{ |attrs| suggestion.from == attrs['rvm'] }
|
121
|
+
entry['rvm'] = suggestion.to.to_s
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def updated_content
|
128
|
+
return @updated_content if @updated_content
|
129
|
+
|
130
|
+
updater = Updater.new(original_content)
|
131
|
+
|
132
|
+
suggestions.each do |suggestion|
|
133
|
+
updater = updater.apply_suggestion(suggestion)
|
134
|
+
end
|
135
|
+
|
136
|
+
@updated_content = updater.content
|
137
|
+
end
|
138
|
+
|
139
|
+
def rvm_versions
|
140
|
+
@rvm_versions ||= Array(original_object['rvm']).map(&Version.method(:new))
|
141
|
+
end
|
142
|
+
|
143
|
+
def allow_failures_versions
|
144
|
+
@allow_failures_versions ||= matrix_versions(original_object, 'allow_failures')
|
145
|
+
end
|
146
|
+
|
147
|
+
def exclude_versions
|
148
|
+
@exclude_versions ||= matrix_versions(original_object, 'exclude')
|
149
|
+
end
|
150
|
+
|
151
|
+
def include_versions
|
152
|
+
@include_versions ||= matrix_versions(original_object, 'include')
|
153
|
+
end
|
154
|
+
|
64
155
|
def matrix_versions(yaml, key)
|
65
156
|
return [] unless (matrix = yaml['matrix'])
|
66
157
|
return [] unless (list = matrix[key])
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'psych'
|
2
|
+
|
3
|
+
module TravisCheckRubies
|
4
|
+
class Updater
|
5
|
+
attr_reader :content
|
6
|
+
|
7
|
+
def initialize(content)
|
8
|
+
@content = content
|
9
|
+
end
|
10
|
+
|
11
|
+
def apply_suggestion(suggestion)
|
12
|
+
lines = content.lines
|
13
|
+
|
14
|
+
if suggestion.section == 'rvm'
|
15
|
+
apply_rvm_suggestion(lines, suggestion)
|
16
|
+
else
|
17
|
+
apply_matrix_suggestion(lines, suggestion)
|
18
|
+
end
|
19
|
+
|
20
|
+
self.class.new lines.join('')
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def apply_rvm_suggestion(lines, suggestion)
|
26
|
+
node = rvm_node.children.find{ |node| suggestion.from == node.to_ruby }
|
27
|
+
|
28
|
+
lines[node.start_line] = suggestion.choices.map do |version|
|
29
|
+
log_change suggestion.from, version, 'rvm'
|
30
|
+
line_with_version_change(lines, node, suggestion.from, version)
|
31
|
+
end.join('')
|
32
|
+
end
|
33
|
+
|
34
|
+
def apply_matrix_suggestion(lines, suggestion)
|
35
|
+
section_node = matrix_section_node(suggestion.section)
|
36
|
+
|
37
|
+
entry_node = section_node.children.find{ |node| suggestion.from == node.to_ruby['rvm'] }
|
38
|
+
|
39
|
+
node = fetch_node_mapping(entry_node, 'rvm')
|
40
|
+
|
41
|
+
log_change suggestion.from, suggestion.to, 'matrix'
|
42
|
+
lines[node.start_line] = line_with_version_change(lines, node, suggestion.from, suggestion.to)
|
43
|
+
end
|
44
|
+
|
45
|
+
def log_change(from, to, section)
|
46
|
+
puts "#{from} -> #{to} \# #{section} section"
|
47
|
+
end
|
48
|
+
|
49
|
+
def root
|
50
|
+
@root ||= Psych::Parser.new(Psych::TreeBuilder.new).parse(content).handler.root.children[0].children[0]
|
51
|
+
end
|
52
|
+
|
53
|
+
def rvm_node
|
54
|
+
fetch_node_mapping(root, 'rvm').tap do |rvm_node|
|
55
|
+
assert_type rvm_node, Psych::Nodes::Sequence
|
56
|
+
fail "Expected block style: #{rvm_node.to_ruby}" unless rvm_node.style == Psych::Nodes::Sequence::BLOCK
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def matrix_section_node(section)
|
61
|
+
matrix_node = fetch_node_mapping(root, 'matrix')
|
62
|
+
|
63
|
+
fetch_node_mapping(matrix_node, section).tap do |section_node|
|
64
|
+
assert_type section_node, Psych::Nodes::Sequence
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def fetch_node_mapping(mapping, key)
|
69
|
+
assert_type mapping, Psych::Nodes::Mapping
|
70
|
+
|
71
|
+
_, node = mapping.children.each_cons(2).find{ |key_node, _| key_node.to_ruby == key }
|
72
|
+
|
73
|
+
fail "Didn't find key #{key.inspect} in #{mapping.to_ruby}" unless node
|
74
|
+
|
75
|
+
node
|
76
|
+
end
|
77
|
+
|
78
|
+
def line_with_version_change(lines, node, from, to)
|
79
|
+
assert_type node, Psych::Nodes::Scalar
|
80
|
+
|
81
|
+
line = lines[node.start_line]
|
82
|
+
|
83
|
+
before = line[0...node.start_column]
|
84
|
+
excerpt = line[node.start_column...node.end_column]
|
85
|
+
after = line[node.end_column..-1]
|
86
|
+
|
87
|
+
fail "Didn't find #{from.to_s} in #{line}" unless excerpt.sub!(from.to_s, to.to_s)
|
88
|
+
|
89
|
+
"#{before}#{excerpt}#{after}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def assert_type(node, expected_class)
|
93
|
+
return if node.is_a?(expected_class)
|
94
|
+
|
95
|
+
fail "Expected a #{expected_class}, got #{node.class}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -1,29 +1,20 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
require 'fspath'
|
3
1
|
require 'set'
|
4
|
-
|
2
|
+
|
3
|
+
require_relative 'rvm_index'
|
4
|
+
require_relative 'travis_index'
|
5
5
|
|
6
6
|
module TravisCheckRubies
|
7
7
|
class Version
|
8
|
-
ROOT_URL = 'https://rubies.travis-ci.org/'
|
9
|
-
CACHE_TIME = 24 * 60 * 60
|
10
|
-
|
11
8
|
class << self
|
12
9
|
def convert(version_or_string)
|
13
10
|
version_or_string.is_a?(self) ? version_or_string : new(version_or_string)
|
14
11
|
end
|
15
12
|
|
16
13
|
def available
|
17
|
-
@available ||=
|
18
|
-
index_urls.select do |url|
|
19
|
-
url.start_with?(base_url)
|
20
|
-
end.map do |url|
|
21
|
-
new(url[%r{([^/]+)\.tar\.(?:gz|bz2)$}, 1])
|
22
|
-
end.sort
|
23
|
-
end
|
14
|
+
@available ||= [TravisIndex, RvmIndex].map(&:new).map(&:version_strings).inject(:|).map{ |s| new(s) }.sort
|
24
15
|
end
|
25
16
|
|
26
|
-
def update(version, parts: 0..2, allow_pre: false, intermediary: true, exclude: [])
|
17
|
+
def update(version, parts: 0..2, allow_pre: false, intermediary: true, exclude: [], conservative: false)
|
27
18
|
version = convert(version)
|
28
19
|
return unless version.version_parts
|
29
20
|
|
@@ -66,53 +57,12 @@ module TravisCheckRubies
|
|
66
57
|
updates = {}
|
67
58
|
has = Set.new
|
68
59
|
versions.uniq.sort.reverse_each do |version|
|
69
|
-
deduplicated = (update(version, options) || [version]).select{ |v| has.add?(v) }
|
60
|
+
deduplicated = (update(version, **options) || [version]).select{ |v| has.add?(v) }
|
70
61
|
updates[version] = [version] == deduplicated ? nil : deduplicated
|
71
62
|
end
|
72
63
|
|
73
64
|
Hash[versions.map{ |v| [v, updates[v]] }]
|
74
65
|
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
def cache_path
|
79
|
-
@cache_path ||= FSPath(ENV['XDG_CACHE_HOME'] || '~/.cache').expand_path / 'travis_check_rubies.txt'
|
80
|
-
end
|
81
|
-
|
82
|
-
def index_urls
|
83
|
-
@index_urls ||= (cached_index_data || fetch_index_data).split("\n")
|
84
|
-
end
|
85
|
-
|
86
|
-
def cached_index_data
|
87
|
-
return unless cache_path.size?
|
88
|
-
return unless cache_path.mtime + CACHE_TIME > Time.now
|
89
|
-
data = cache_path.read
|
90
|
-
data if data.start_with?(ROOT_URL)
|
91
|
-
end
|
92
|
-
|
93
|
-
def fetch_index_data
|
94
|
-
data = Net::HTTP.get(URI(ROOT_URL + 'index.txt'))
|
95
|
-
|
96
|
-
cache_path.dirname.mkpath
|
97
|
-
FSPath.temp_file('travis_check_rubies', cache_path.dirname) do |f|
|
98
|
-
f.write(data)
|
99
|
-
f.path.rename(cache_path)
|
100
|
-
end
|
101
|
-
|
102
|
-
data
|
103
|
-
end
|
104
|
-
|
105
|
-
def base_url
|
106
|
-
@base_url ||= if ENV['TRAVIS']
|
107
|
-
sys_path = `rvm debug`[/(?:system|remote.path):\s*"(.*?)"/, 1]
|
108
|
-
"#{ROOT_URL}#{sys_path}/"
|
109
|
-
else
|
110
|
-
base_ubuntu_url = "#{ROOT_URL}ubuntu/"
|
111
|
-
first_ubuntu_url = index_urls.sort.find{ |url| url.start_with?(base_ubuntu_url) }
|
112
|
-
fail "First ubuntu url (#{ROOT_URL}ubuntu/*) not fount out of:\n#{index_urls.join("\n")}" unless first_ubuntu_url
|
113
|
-
first_ubuntu_url[%r{^.*/}]
|
114
|
-
end
|
115
|
-
end
|
116
66
|
end
|
117
67
|
|
118
68
|
include Comparable
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'travis_check_rubies/fetcher'
|
3
|
+
|
4
|
+
describe TravisCheckRubies::Fetcher do
|
5
|
+
describe '#data' do
|
6
|
+
subject{ described_class.new(url) }
|
7
|
+
|
8
|
+
let(:url){ 'https://example.com/index.txt' }
|
9
|
+
let(:cache_path){ FSPath.temp_file_path }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(subject).to receive(:cache_path).and_return(cache_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns data from url' do
|
16
|
+
allow(Net::HTTP).to receive(:get).with(URI(url)).
|
17
|
+
and_return("one\ntwo\nthree")
|
18
|
+
|
19
|
+
expect(subject.data).to eq("one\ntwo\nthree")
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'caches result' do
|
23
|
+
allow(Net::HTTP).to receive(:get).with(URI(url)).
|
24
|
+
once.and_return("a\nb\nc")
|
25
|
+
|
26
|
+
3.times{ expect(subject.data).to eq("a\nb\nc") }
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'reads cache from file if it is new' do
|
30
|
+
cache_path.write "foo\nbar"
|
31
|
+
allow(cache_path).to receive(:size?).and_return(616)
|
32
|
+
allow(cache_path).to receive(:mtime).and_return(Time.now - described_class::CACHE_TIME / 2)
|
33
|
+
|
34
|
+
expect(Net::HTTP).not_to receive(:get)
|
35
|
+
expect(subject.data).to eq("foo\nbar")
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'writes cache file if it is stale' do
|
39
|
+
allow(cache_path).to receive(:size?).and_return(616)
|
40
|
+
allow(cache_path).to receive(:mtime).and_return(Time.now - described_class::CACHE_TIME * 2)
|
41
|
+
allow(Net::HTTP).to receive(:get).with(URI(url)).
|
42
|
+
once.and_return("brave\nnew\nworld")
|
43
|
+
|
44
|
+
expect(subject.data).to eq("brave\nnew\nworld")
|
45
|
+
expect(cache_path.read).to eq("brave\nnew\nworld")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'travis_check_rubies/travis_index'
|
3
|
+
|
4
|
+
describe TravisCheckRubies::TravisIndex do
|
5
|
+
describe '#base_url' do
|
6
|
+
context 'when env variable TRAVIS is not set' do
|
7
|
+
let(:env_travis){ nil }
|
8
|
+
|
9
|
+
it 'gets base_url from first ubuntu url in index' do
|
10
|
+
allow(TravisCheckRubies::TravisYml).to receive(:new)
|
11
|
+
.and_return instance_double(TravisCheckRubies::TravisYml, dist: 'trusty')
|
12
|
+
|
13
|
+
expect(subject.send(:base_url)).to eq('https://rubies.travis-ci.org/ubuntu/14.04/x86_64/')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#version_strings' do
|
19
|
+
it 'gets versions from index urls matching base_url' do
|
20
|
+
allow(subject).to receive(:index_urls).and_return(%w[
|
21
|
+
https://rubies.travis-ci.org/osx/AAA/1.tar.gz
|
22
|
+
https://rubies.travis-ci.org/ubuntu/ZZZ/2.tar.gz
|
23
|
+
https://rubies.travis-ci.org/ubuntu/BBB/4.tar.gz
|
24
|
+
https://rubies.travis-ci.org/ubuntu/BBB/3.tar.bz2
|
25
|
+
])
|
26
|
+
allow(subject).to receive(:base_url).and_return('https://rubies.travis-ci.org/ubuntu/BBB/')
|
27
|
+
|
28
|
+
expect(subject.version_strings).to match_array(%w[3 4])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'travis_check_rubies/updater'
|
3
|
+
|
4
|
+
describe TravisCheckRubies::Updater do
|
5
|
+
describe '#apply_suggestion' do
|
6
|
+
subject{ described_class.new(content).apply_suggestion(suggestion) }
|
7
|
+
|
8
|
+
context 'for rvm change suggestion' do
|
9
|
+
let(:content) do
|
10
|
+
<<~YAML
|
11
|
+
language: ruby
|
12
|
+
rvm: # rvm
|
13
|
+
- '2.1.3' # foo
|
14
|
+
- '2.2.8' # bar
|
15
|
+
- '2.5.0' # baz
|
16
|
+
before_script:
|
17
|
+
- env # env
|
18
|
+
YAML
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'removing version' do
|
22
|
+
let(:suggestion){ double(section: 'rvm', from: '2.2.8', choices: []) }
|
23
|
+
|
24
|
+
let(:expected) do
|
25
|
+
<<~YAML
|
26
|
+
language: ruby
|
27
|
+
rvm: # rvm
|
28
|
+
- '2.1.3' # foo
|
29
|
+
- '2.5.0' # baz
|
30
|
+
before_script:
|
31
|
+
- env # env
|
32
|
+
YAML
|
33
|
+
end
|
34
|
+
|
35
|
+
it{ is_expected.to have_attributes(content: expected) }
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'changing to one version' do
|
39
|
+
let(:suggestion){ double(section: 'rvm', from: '2.2.8', choices: [double(to_s: '2.2.9')]) }
|
40
|
+
|
41
|
+
let(:expected) do
|
42
|
+
<<~YAML
|
43
|
+
language: ruby
|
44
|
+
rvm: # rvm
|
45
|
+
- '2.1.3' # foo
|
46
|
+
- '2.2.9' # bar
|
47
|
+
- '2.5.0' # baz
|
48
|
+
before_script:
|
49
|
+
- env # env
|
50
|
+
YAML
|
51
|
+
end
|
52
|
+
|
53
|
+
it{ is_expected.to have_attributes(content: expected) }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'changing to multiple versions' do
|
57
|
+
let(:suggestion){ double(section: 'rvm', from: '2.2.8', choices: [double(to_s: '2.2.9'), double(to_s: '2.3.4')]) }
|
58
|
+
|
59
|
+
let(:expected) do
|
60
|
+
<<~YAML
|
61
|
+
language: ruby
|
62
|
+
rvm: # rvm
|
63
|
+
- '2.1.3' # foo
|
64
|
+
- '2.2.9' # bar
|
65
|
+
- '2.3.4' # bar
|
66
|
+
- '2.5.0' # baz
|
67
|
+
before_script:
|
68
|
+
- env # env
|
69
|
+
YAML
|
70
|
+
end
|
71
|
+
|
72
|
+
it{ is_expected.to have_attributes(content: expected) }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'for matrix change suggestion' do
|
77
|
+
let(:content) do
|
78
|
+
<<~YAML
|
79
|
+
language: ruby
|
80
|
+
before_script:
|
81
|
+
- env # env
|
82
|
+
matrix:
|
83
|
+
allow_failures:
|
84
|
+
- rvm: '2.2.8' # foo
|
85
|
+
exclude:
|
86
|
+
- rvm: '2.2.8' # bar
|
87
|
+
include:
|
88
|
+
- rvm: '2.1.3' # foo
|
89
|
+
- rvm: '2.2.8' # bar
|
90
|
+
- rvm: '2.2.8' # baz
|
91
|
+
YAML
|
92
|
+
end
|
93
|
+
|
94
|
+
let(:suggestion){ double(section: 'include', from: '2.2.8', to: double(to_s: '2.2.9')) }
|
95
|
+
|
96
|
+
let(:expected) do
|
97
|
+
<<~YAML
|
98
|
+
language: ruby
|
99
|
+
before_script:
|
100
|
+
- env # env
|
101
|
+
matrix:
|
102
|
+
allow_failures:
|
103
|
+
- rvm: '2.2.8' # foo
|
104
|
+
exclude:
|
105
|
+
- rvm: '2.2.8' # bar
|
106
|
+
include:
|
107
|
+
- rvm: '2.1.3' # foo
|
108
|
+
- rvm: '2.2.9' # bar
|
109
|
+
- rvm: '2.2.8' # baz
|
110
|
+
YAML
|
111
|
+
end
|
112
|
+
|
113
|
+
it{ is_expected.to have_attributes(content: expected) }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -10,12 +10,6 @@ describe TravisCheckRubies::Version do
|
|
10
10
|
strs.map{ |str| described_class.new(str) }
|
11
11
|
end
|
12
12
|
|
13
|
-
def cleanup_instance_variables(o)
|
14
|
-
o.instance_variables.each do |name|
|
15
|
-
o.remove_instance_variable(name)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
13
|
describe 'parsing' do
|
20
14
|
{
|
21
15
|
'1.2.3-pre1' => {
|
@@ -202,116 +196,12 @@ describe TravisCheckRubies::Version do
|
|
202
196
|
end
|
203
197
|
end
|
204
198
|
|
205
|
-
describe '.index_urls' do
|
206
|
-
let(:cache_path){ FSPath.temp_file_path }
|
207
|
-
|
208
|
-
before do
|
209
|
-
cleanup_instance_variables(described_class)
|
210
|
-
allow(described_class).to receive(:cache_path).and_return(cache_path)
|
211
|
-
end
|
212
|
-
|
213
|
-
it 'returns urls from text index of rubies.travis-ci.org' do
|
214
|
-
allow(Net::HTTP).to receive(:get).with(URI('https://rubies.travis-ci.org/index.txt')).
|
215
|
-
and_return("one\ntwo\nthree")
|
216
|
-
|
217
|
-
expect(described_class.send(:index_urls)).to eq(%w[one two three])
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'caches result' do
|
221
|
-
allow(Net::HTTP).to receive(:get).with(URI('https://rubies.travis-ci.org/index.txt')).
|
222
|
-
once.and_return("a\nb\nc")
|
223
|
-
|
224
|
-
3.times{ expect(described_class.send(:index_urls)).to eq(%w[a b c]) }
|
225
|
-
end
|
226
|
-
|
227
|
-
it 'reads cache from file if it is new' do
|
228
|
-
cache_path.write "https://rubies.travis-ci.org/foo"
|
229
|
-
allow(cache_path).to receive(:size?).and_return(616)
|
230
|
-
allow(cache_path).to receive(:mtime).and_return(Time.now - described_class::CACHE_TIME / 2)
|
231
|
-
|
232
|
-
expect(Net::HTTP).not_to receive(:get)
|
233
|
-
expect(described_class.send(:index_urls)).to eq(%w[https://rubies.travis-ci.org/foo])
|
234
|
-
end
|
235
|
-
|
236
|
-
it 'ignores bad cache' do
|
237
|
-
cache_path.write "http://rubies.travis-ci.org/foo"
|
238
|
-
allow(cache_path).to receive(:size?).and_return(616)
|
239
|
-
allow(cache_path).to receive(:mtime).and_return(Time.now - described_class::CACHE_TIME / 2)
|
240
|
-
|
241
|
-
allow(Net::HTTP).to receive(:get).with(URI('https://rubies.travis-ci.org/index.txt')).
|
242
|
-
once.and_return("brave\nnew\nworld")
|
243
|
-
expect(described_class.send(:index_urls)).to eq(%w[brave new world])
|
244
|
-
expect(cache_path.read).to eq("brave\nnew\nworld")
|
245
|
-
end
|
246
|
-
|
247
|
-
it 'writes cache file if it is stale' do
|
248
|
-
allow(cache_path).to receive(:size?).and_return(616)
|
249
|
-
allow(cache_path).to receive(:mtime).and_return(Time.now - described_class::CACHE_TIME * 2)
|
250
|
-
allow(Net::HTTP).to receive(:get).with(URI('https://rubies.travis-ci.org/index.txt')).
|
251
|
-
once.and_return("brave\nnew\nworld")
|
252
|
-
|
253
|
-
expect(described_class.send(:index_urls)).to eq(%w[brave new world])
|
254
|
-
expect(cache_path.read).to eq("brave\nnew\nworld")
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
describe '.base_url' do
|
259
|
-
before do
|
260
|
-
cleanup_instance_variables(described_class)
|
261
|
-
allow(ENV).to receive(:[]).with('TRAVIS').and_return(env_travis)
|
262
|
-
end
|
263
|
-
|
264
|
-
context 'when env variable TRAVIS is set' do
|
265
|
-
let(:env_travis){ 'true' }
|
266
|
-
|
267
|
-
it 'gets base_url from rvm debug' do
|
268
|
-
allow(described_class).to receive(:`).with('rvm debug').
|
269
|
-
and_return(%Q{ foo: "xxx" \n system: "XXX/YYY" \n bar: "yyy" })
|
270
|
-
|
271
|
-
expect(described_class.send(:base_url)).to eq('https://rubies.travis-ci.org/XXX/YYY/')
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
context 'when env variable TRAVIS is not set' do
|
276
|
-
let(:env_travis){ nil }
|
277
|
-
|
278
|
-
it 'gets base_url from first ubuntu url in index' do
|
279
|
-
allow(described_class).to receive(:index_urls).and_return(%w[
|
280
|
-
https://rubies.travis-ci.org/osx/AAA/1.tar.gz
|
281
|
-
https://rubies.travis-ci.org/ubuntu/ZZZ/2.tar.gz
|
282
|
-
https://rubies.travis-ci.org/ubuntu/BBB/3.tar.gz
|
283
|
-
])
|
284
|
-
|
285
|
-
expect(described_class.send(:base_url)).to eq('https://rubies.travis-ci.org/ubuntu/BBB/')
|
286
|
-
end
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
199
|
describe '.available' do
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
it 'gets sorted versions from index urls matching base_url' do
|
296
|
-
allow(described_class).to receive(:index_urls).and_return(%w[
|
297
|
-
https://rubies.travis-ci.org/osx/AAA/1.tar.gz
|
298
|
-
https://rubies.travis-ci.org/ubuntu/ZZZ/2.tar.gz
|
299
|
-
https://rubies.travis-ci.org/ubuntu/BBB/4.tar.gz
|
300
|
-
https://rubies.travis-ci.org/ubuntu/BBB/3.tar.bz2
|
301
|
-
])
|
302
|
-
allow(described_class).to receive(:base_url).and_return('https://rubies.travis-ci.org/ubuntu/BBB/')
|
303
|
-
|
304
|
-
expect(described_class.available).to eq([v('3'), v('4')])
|
305
|
-
end
|
306
|
-
|
307
|
-
it 'caches result' do
|
308
|
-
allow(described_class).to receive(:index_urls).once.and_return(%w[
|
309
|
-
https://rubies.travis-ci.org/ubuntu/CCC/a.tar.gz
|
310
|
-
https://rubies.travis-ci.org/ubuntu/CCC/b.tar.bz2
|
311
|
-
])
|
312
|
-
allow(described_class).to receive(:base_url).and_return('https://rubies.travis-ci.org/ubuntu/CCC/')
|
200
|
+
it 'gets distinct sorted versions by combining indexes' do
|
201
|
+
allow(TravisCheckRubies::TravisIndex).to receive(:new).and_return(double(version_strings: %w[e d c b a]))
|
202
|
+
allow(TravisCheckRubies::RvmIndex).to receive(:new).and_return(double(version_strings: %w[d e f g h]))
|
313
203
|
|
314
|
-
|
204
|
+
expect(described_class.available).to eq(vs(%w[a b c d e f g h]))
|
315
205
|
end
|
316
206
|
end
|
317
207
|
|
data/travis_check_rubies.gemspec
CHANGED
@@ -2,21 +2,28 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'travis_check_rubies'
|
5
|
-
s.version = '0.
|
5
|
+
s.version = '0.6.0'
|
6
6
|
s.summary = 'Are you using the latest rubies in .travis.yml?'
|
7
7
|
s.description = 'Check if `.travis.yml` specifies latest available rubies from listed on https://rubies.travis-ci.org and propose changes'
|
8
|
-
s.homepage = "
|
8
|
+
s.homepage = "https://github.com/toy/#{s.name}"
|
9
9
|
s.authors = ['Ivan Kuchin']
|
10
10
|
s.license = 'MIT'
|
11
11
|
|
12
|
+
s.metadata = {
|
13
|
+
'bug_tracker_uri' => "https://github.com/toy/#{s.name}/issues",
|
14
|
+
'documentation_uri' => "https://www.rubydoc.info/gems/#{s.name}/#{s.version}",
|
15
|
+
'source_code_uri' => "https://github.com/toy/#{s.name}",
|
16
|
+
}
|
17
|
+
|
12
18
|
s.files = `git ls-files`.split("\n")
|
13
19
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
20
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
15
21
|
s.require_paths = %w[lib]
|
16
22
|
|
17
|
-
s.required_ruby_version = '>= 2.
|
23
|
+
s.required_ruby_version = '>= 2.3.0'
|
18
24
|
|
19
25
|
s.add_runtime_dependency 'fspath', '~> 3.0'
|
26
|
+
s.add_runtime_dependency 'psych', '~> 3.0'
|
20
27
|
|
21
28
|
s.add_development_dependency 'rspec', '~> 3.0'
|
22
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: travis_check_rubies
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Kuchin
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fspath
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: psych
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rspec
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -40,7 +54,7 @@ dependencies:
|
|
40
54
|
version: '3.0'
|
41
55
|
description: Check if `.travis.yml` specifies latest available rubies from listed
|
42
56
|
on https://rubies.travis-ci.org and propose changes
|
43
|
-
email:
|
57
|
+
email:
|
44
58
|
executables:
|
45
59
|
- travis_check_rubies
|
46
60
|
extensions: []
|
@@ -53,15 +67,25 @@ files:
|
|
53
67
|
- README.markdown
|
54
68
|
- bin/travis_check_rubies
|
55
69
|
- lib/travis_check_rubies.rb
|
70
|
+
- lib/travis_check_rubies/fetcher.rb
|
71
|
+
- lib/travis_check_rubies/rvm_index.rb
|
72
|
+
- lib/travis_check_rubies/travis_index.rb
|
56
73
|
- lib/travis_check_rubies/travis_yml.rb
|
74
|
+
- lib/travis_check_rubies/updater.rb
|
57
75
|
- lib/travis_check_rubies/version.rb
|
76
|
+
- spec/travis_check_rubies/fetcher_spec.rb
|
77
|
+
- spec/travis_check_rubies/travis_index_spec.rb
|
78
|
+
- spec/travis_check_rubies/updater_spec.rb
|
58
79
|
- spec/travis_check_rubies/version_spec.rb
|
59
80
|
- travis_check_rubies.gemspec
|
60
|
-
homepage:
|
81
|
+
homepage: https://github.com/toy/travis_check_rubies
|
61
82
|
licenses:
|
62
83
|
- MIT
|
63
|
-
metadata:
|
64
|
-
|
84
|
+
metadata:
|
85
|
+
bug_tracker_uri: https://github.com/toy/travis_check_rubies/issues
|
86
|
+
documentation_uri: https://www.rubydoc.info/gems/travis_check_rubies/0.6.0
|
87
|
+
source_code_uri: https://github.com/toy/travis_check_rubies
|
88
|
+
post_install_message:
|
65
89
|
rdoc_options: []
|
66
90
|
require_paths:
|
67
91
|
- lib
|
@@ -69,17 +93,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
69
93
|
requirements:
|
70
94
|
- - ">="
|
71
95
|
- !ruby/object:Gem::Version
|
72
|
-
version: 2.
|
96
|
+
version: 2.3.0
|
73
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
98
|
requirements:
|
75
99
|
- - ">="
|
76
100
|
- !ruby/object:Gem::Version
|
77
101
|
version: '0'
|
78
102
|
requirements: []
|
79
|
-
|
80
|
-
|
81
|
-
signing_key:
|
103
|
+
rubygems_version: 3.1.5
|
104
|
+
signing_key:
|
82
105
|
specification_version: 4
|
83
106
|
summary: Are you using the latest rubies in .travis.yml?
|
84
107
|
test_files:
|
108
|
+
- spec/travis_check_rubies/fetcher_spec.rb
|
109
|
+
- spec/travis_check_rubies/travis_index_spec.rb
|
110
|
+
- spec/travis_check_rubies/updater_spec.rb
|
85
111
|
- spec/travis_check_rubies/version_spec.rb
|