travis_check_rubies 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZjA1NTQ3ZjAwMjE4YmI4MzBkZGE2MGMxOWZiZmY0MDZiNzA3YWNjZQ==
5
- data.tar.gz: !binary |-
6
- YzMyMGIwYzk2NzM4NzI3NjUxMGE0MmU0NmVkOTEzN2U3NmU4YzkwOQ==
2
+ SHA1:
3
+ metadata.gz: bfd262c7e986d7ca949f6811db98ef99f2aab55e
4
+ data.tar.gz: 65c395fa0c08ae67e8e0c35f526891091f02ab8d
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MTk2MDVjYTJmYjY0MDA2MzdiMDFjZTE3Nzc5NjI3MzA2ZWVkMzkwNjc2MzJj
10
- MTE3YmI3NjkxYzE2YjBlYzg5ZjFjYzQyZjVlZmJmYTViMGRiODUxNjg1MGRj
11
- YWQ4Mzk0YmFjNDgzMDZlMDAyOGUyZmZhNzEyMWQxMWYzMmY3OWU=
12
- data.tar.gz: !binary |-
13
- NWM2YzI5YTExMzdkZmEyM2Y4ZTdjOGY5NjBkZDk4Mzc0YzJhNGFhMjc5NzE1
14
- MmI4YTU2MTZjNGJmZDM5NDdhMWNiMGZmZGFjNTBjZjRhODQxOGVjNjI3YTNl
15
- NmVlNTEzMWQwMjBiNmY1MTIzMzk5NzJjNmViODhmMjdjNjdjOWY=
6
+ metadata.gz: 86c99d9aa7055c649b3611d29181429f25b4997c253504c4af5740973606f8838eeb466355d9cb961f07e1e79556d76ef6accb3bc2ad42abcd5767a2054a6b44
7
+ data.tar.gz: d71305cf683e36b261330a182b2c77de094e4f6be19b795aed62908091323abb8ad319b3dd37db1b09a9f0879f30d576787be107815fe6e0f9ffd50f2ba7a8f4
data/.travis.yml CHANGED
@@ -1,14 +1,20 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - '1.8.7-p371'
5
- - '1.9.3-p551'
6
4
  - '2.0.0-p648'
7
5
  - '2.1.10'
8
6
  - '2.2.6'
9
7
  - '2.3.3'
10
8
  - '2.4.0'
11
- - 'jruby-1.7.26'
12
9
  - 'jruby-9.0.5.0'
13
10
  - 'jruby-9.1.5.0'
14
- script: bundle exec travis_check_rubies
11
+ script:
12
+ - bundle exec rspec
13
+ - bundle exec travis_check_rubies
14
+ matrix:
15
+ allow_failures:
16
+ - rvm: 'jruby-9.0.5.0'
17
+ exclude:
18
+ - rvm: 'jruby-9.0.5.0'
19
+ include:
20
+ - rvm: 'jruby-9.0.5.0'
data/README.markdown CHANGED
@@ -29,7 +29,7 @@ Merge into your `.travis.yml`:
29
29
  matrix:
30
30
  include:
31
31
  - env: CHECK_RUBIES=✓
32
- rvm: '2'
32
+ rvm: '2.4.0'
33
33
  script: bundle exec travis_check_rubies
34
34
  ```
35
35
 
@@ -1,24 +1,36 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'travis_check_rubies/version'
3
+ require 'travis_check_rubies/travis_yml'
4
+ require 'optparse'
4
5
 
5
- matches = TravisCheckRubies::Version.matches
6
- if matches.values.any?
7
- ansi_red = `tput setaf 1 2>/dev/null`
8
- ansi_green = `tput setaf 2 2>/dev/null`
9
- ansi_reset = `tput sgr0 2>/dev/null`
10
- puts 'Suggested changes:'
11
- matches.each do |version, matched_versions|
12
- if !matched_versions || matched_versions.include?(version)
13
- puts " #{version}"
14
- else
15
- puts "#{ansi_red}-#{version}#{ansi_reset}"
16
- end
17
- if matched_versions
18
- (matched_versions - [version]).each do |matched_version|
19
- puts "#{ansi_green}+#{matched_version}#{ansi_reset}"
20
- end
21
- end
6
+ options = {}
7
+
8
+ op = OptionParser.new
9
+ op.on('--parts N|M..N', 'Match updates by how many parts (0..2 by default)') do |parts|
10
+ options[:parts] = case parts
11
+ when /\A\d+\z/
12
+ parts.to_i
13
+ when /\A(\d+)..(\d+)\z/
14
+ $1.to_i..$2.to_i
15
+ else
16
+ fail "Expected number N or range M..N, got #{parts}"
22
17
  end
23
- abort
24
18
  end
19
+ op.on('--[no-]allow-pre', 'Allow matching pre releases (false by default)') do |allow_pre|
20
+ options[:allow_pre] = allow_pre
21
+ end
22
+ op.on('--[no-]intermediary', 'Include all latest version distinct by maximum matchable '\
23
+ 'parts, like 2.3.X when current is 2.2.X and latest is 2.4.X (true by default)') do |intermediary|
24
+ options[:intermediary] = intermediary
25
+ end
26
+ op.on('--exclude V,V,V', Array, 'Exclude matching versions') do |exclude|
27
+ options[:exclude] = exclude
28
+ end
29
+ begin
30
+ op.parse!
31
+ rescue => e
32
+ abort "#{e}\n\n#{op.help}"
33
+ end
34
+
35
+ suggestions = TravisCheckRubies::TravisYml.new.suggestions(options)
36
+ abort suggestions if suggestions
@@ -0,0 +1,70 @@
1
+ require 'yaml'
2
+ require 'travis_check_rubies/version'
3
+
4
+ module TravisCheckRubies
5
+ class TravisYml
6
+ attr_reader :path
7
+ attr_reader :versions, :allow_failures_versions, :exclude_versions, :include_versions
8
+
9
+ def initialize(path = '.travis.yml')
10
+ @path = path
11
+
12
+ yaml = YAML.load_file(path)
13
+ @versions = Array(yaml['rvm']).map(&Version.method(:new))
14
+ @allow_failures_versions = matrix_versions(yaml, 'allow_failures')
15
+ @exclude_versions = matrix_versions(yaml, 'exclude')
16
+ @include_versions = matrix_versions(yaml, 'include')
17
+ end
18
+
19
+ def suggestions(options)
20
+ suggestions = Hash.new{ |h, k| h[k] = [] }
21
+
22
+ updates = Version.updates(versions, options)
23
+
24
+ versions.each do |version|
25
+ next unless (for_version = updates[version])
26
+ suggestions['rvm'] << "#{version} -> #{for_version.join(', ')}"
27
+ end
28
+
29
+ allow_failures_versions.each do |version|
30
+ next if versions.include?(version)
31
+ next if include_versions.include?(version)
32
+ suggestions['matrix.allow_failures'] << "#{version} in matrix.allow_failures is not in rvm or include list"
33
+ end
34
+
35
+ exclude_versions.each do |version|
36
+ next if versions.include?(version)
37
+ suggestions['matrix.exclude'] << "#{version} in matrix.exclude is not in rvm list"
38
+ end
39
+
40
+ {
41
+ 'matrix.allow_failures' => allow_failures_versions,
42
+ 'matrix.exclude' => exclude_versions,
43
+ }.each do |section, versions|
44
+ versions.each do |version|
45
+ next unless (for_version = updates[version])
46
+ suggestions[section] << "#{version} -> #{for_version.join(', ')}"
47
+ end
48
+ end
49
+
50
+ include_versions.each do |version|
51
+ next unless (for_version = Version.update(version, options))
52
+ next if for_version.include?(version)
53
+ suggestions['matrix.include'] << "#{version} -> #{for_version.join(', ')}"
54
+ end
55
+
56
+ return if suggestions.empty?
57
+ suggestions.map do |section, lines|
58
+ "#{section}:\n#{lines.map{ |line| " #{line}" }.join("\n")}"
59
+ end.join("\n")
60
+ end
61
+
62
+ private
63
+
64
+ def matrix_versions(yaml, key)
65
+ return [] unless (matrix = yaml['matrix'])
66
+ return [] unless (list = matrix[key])
67
+ Array(list).map{ |attrs| attrs['rvm'] }.compact.map(&Version.method(:new))
68
+ end
69
+ end
70
+ end
@@ -1,12 +1,17 @@
1
1
  require 'net/http'
2
+ require 'fspath'
2
3
  require 'set'
3
4
  require 'uri'
4
- require 'yaml'
5
5
 
6
6
  module TravisCheckRubies
7
7
  class Version
8
+ ROOT_URL = 'http://rubies.travis-ci.org/'
9
+ CACHE_TIME = 24 * 60 * 60
10
+
8
11
  class << self
9
- ROOT_URL = 'http://rubies.travis-ci.org/'
12
+ def convert(version_or_string)
13
+ version_or_string.is_a?(self) ? version_or_string : new(version_or_string)
14
+ end
10
15
 
11
16
  def available
12
17
  @available ||= begin
@@ -14,36 +19,81 @@ module TravisCheckRubies
14
19
  url.start_with?(base_url)
15
20
  end.map do |url|
16
21
  new(url[%r{([^/]+)\.tar\.(?:gz|bz2)$}, 1])
17
- end
22
+ end.sort
18
23
  end
19
24
  end
20
25
 
21
- def selected
22
- @selected ||= begin
23
- Array(YAML.load_file('.travis.yml')['rvm']).map do |string|
24
- new(string)
26
+ def update(version, parts: 0..2, allow_pre: false, intermediary: true, exclude: [])
27
+ version = convert(version)
28
+ return unless version.version_parts
29
+
30
+ parts = Array(parts)
31
+ exclude = exclude.map{ |ev| convert(ev) }
32
+ ordered = allow_pre ? available : available.partition(&:pre).inject(:+)
33
+ candidates = ordered.reverse.select do |v|
34
+ next unless v.version_parts
35
+ next unless v.match?(version, parts.min)
36
+ next unless v >= version
37
+ next if exclude.any?{ |ev| ev.match?(v, ev.version_parts.length) }
38
+ true
39
+ end
40
+
41
+ updates = if intermediary
42
+ candidates.group_by do |v|
43
+ v.version_parts.take(parts.max)
44
+ end.flat_map do |_, group|
45
+ parts.map do |n|
46
+ group.find{ |v| v.match?(version, n) }
47
+ end
48
+ end
49
+ else
50
+ parts.map do |n|
51
+ candidates.find{ |v| v.match?(version, n) }
25
52
  end
26
53
  end
54
+
55
+ updates.compact!
56
+ updates.uniq!
57
+ updates.sort!
58
+
59
+ updates unless [version] == updates
27
60
  end
28
61
 
29
- def matches
30
- matches = {}
31
- deduplicate = Set.new
32
- available_versioned = available.select(&:version_parts).sort.reverse
33
- selected.select(&:version_parts).sort.reverse.each do |version|
34
- matches[version] = (0..version.version_parts.length).map do |n|
35
- available_versioned.find{ |v| version.match?(v, n) }
36
- end.reverse.select{ |v| deduplicate.add?(v) }
62
+ def updates(versions, **options)
63
+ versions = versions.map{ |v| convert(v) }
64
+
65
+ updates = {}
66
+ has = Set.new
67
+ versions.uniq.sort.reverse_each do |version|
68
+ deduplicated = (update(version, options) || [version]).select{ |v| has.add?(v) }
69
+ updates[version] = [version] == deduplicated ? nil : deduplicated
37
70
  end
38
- Hash[selected.map do |v|
39
- [v, [v] == matches[v] ? nil : matches[v]]
40
- end]
71
+
72
+ Hash[versions.map{ |v| [v, updates[v]] }]
41
73
  end
42
74
 
43
75
  private
44
76
 
77
+ def cache_path
78
+ @cache_path ||= FSPath(ENV['XDG_CACHE_HOME'] || '~/.cache').expand_path / 'travis_check_rubies.txt'
79
+ end
80
+
45
81
  def index_urls
46
- @index_urls ||= Net::HTTP.get(URI(ROOT_URL + 'index.txt')).split("\n")
82
+ @index_urls ||= begin
83
+ if cache_path.size? && cache_path.mtime + CACHE_TIME > Time.now
84
+ cache_path.read
85
+ else
86
+ data = Net::HTTP.get(URI(ROOT_URL + 'index.txt'))
87
+
88
+ cache_path.dirname.mkpath
89
+ FSPath.temp_file('travis_check_rubies', cache_path.dirname) do |f|
90
+ f.write(data)
91
+ f.path.rename(cache_path)
92
+ end
93
+
94
+ data
95
+ end
96
+ end.split("\n")
47
97
  end
48
98
 
49
99
  def base_url
@@ -91,6 +141,10 @@ module TravisCheckRubies
91
141
  match_by(n) == other.match_by(n)
92
142
  end
93
143
 
144
+ def inspect
145
+ "#<#{self.class.name} #{str}>"
146
+ end
147
+
94
148
  protected
95
149
 
96
150
  def compare_by
@@ -103,7 +157,7 @@ module TravisCheckRubies
103
157
  end
104
158
 
105
159
  def match_by(n)
106
- [type, variant, version_parts.take(n)]
160
+ [type, variant, version_parts && version_parts.take(n)]
107
161
  end
108
162
  end
109
163
  end
@@ -0,0 +1,425 @@
1
+ require 'rspec'
2
+ require 'travis_check_rubies/version'
3
+
4
+ describe TravisCheckRubies::Version do
5
+ def v(str)
6
+ described_class.new(str)
7
+ end
8
+
9
+ def vs(strs)
10
+ strs.map{ |str| described_class.new(str) }
11
+ end
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
+ describe 'parsing' do
20
+ {
21
+ '1.2.3-pre1' => {
22
+ version_parts: [1, 2, 3],
23
+ pre: 'pre1',
24
+ },
25
+ 'jruby' => {
26
+ type: 'jruby',
27
+ },
28
+ 'ruby-2.3.4.5-clang' => {
29
+ str: '2.3.4.5-clang',
30
+ version_parts: [2, 3, 4, 5],
31
+ variant: 'clang',
32
+ },
33
+ 'xrb-1000' => {
34
+ type: 'xrb',
35
+ version_parts: [1000],
36
+ },
37
+ '1.5' => {
38
+ version_parts: [1, 5],
39
+ },
40
+ '1.8.4-p616' => {
41
+ version_parts: [1, 8, 4, 616],
42
+ },
43
+ }.each do |version_string, defined_attributes|
44
+ context "of #{version_string}" do
45
+ subject{ v(version_string) }
46
+
47
+ let(:default_attributes) do
48
+ {
49
+ str: version_string,
50
+ type: 'ruby',
51
+ version_parts: nil,
52
+ pre: nil,
53
+ variant: nil,
54
+ }
55
+ end
56
+
57
+ it{ is_expected.to have_attributes(default_attributes.merge(defined_attributes)) }
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#eql?' do
63
+ it 'returns false for different version' do
64
+ expect(v('1.8')).not_to eql(v('1.9'))
65
+ end
66
+
67
+ it 'returns true for equal versions' do
68
+ expect(v('1.8')).to eql(v('1.8'))
69
+ end
70
+
71
+ it 'returns true for same version in different format' do
72
+ expect(v('1.8')).to eql(v('ruby-1.8'))
73
+ end
74
+
75
+ it 'returns true for same version string' do
76
+ expect(v('1.8')).to eql('1.8')
77
+ end
78
+ end
79
+
80
+ describe '#<=>' do
81
+ let(:versions) do
82
+ vs(%w[
83
+ jruby-head
84
+ jruby-1.7.7
85
+ jruby-1.7.26
86
+ jruby-9.0.0.0.pre1
87
+ jruby-9.0.0.0.pre2
88
+ jruby-9.0.0.0
89
+ ruby-1.8.7
90
+ ruby-1.8.7-p371
91
+ ruby-2.0.0-p645
92
+ ruby-2.0.0-p647
93
+ ruby-2.0.0-p647-clang
94
+ ])
95
+ end
96
+
97
+ it 'oders versions using all parts' do
98
+ expect(versions.reverse.sort).to eq(versions)
99
+ end
100
+ end
101
+
102
+ describe '#match?' do
103
+ subject{ v('ruby-1.7.7') }
104
+
105
+ context 'for same version' do
106
+ let(:version){ v('ruby-1.7.7') }
107
+
108
+ it 'matches with any number of parts' do
109
+ (0..4).each{ |n| is_expected.to be_match(version, n) }
110
+ end
111
+ end
112
+
113
+ context 'for different patch version' do
114
+ let(:version){ v('ruby-1.7.8') }
115
+
116
+ it 'matches with 0..2 parts' do
117
+ (0..2).each{ |n| is_expected.to be_match(version, n) }
118
+ end
119
+
120
+ it 'does not match with more parts' do
121
+ (3..4).each{ |n| is_expected.not_to be_match(version, n) }
122
+ end
123
+ end
124
+
125
+ context 'for different minor version' do
126
+ let(:version){ v('ruby-1.8.7') }
127
+
128
+ it 'matches with 0..1 parts' do
129
+ (0..1).each{ |n| is_expected.to be_match(version, n) }
130
+ end
131
+
132
+ it 'does not match with more parts' do
133
+ (2..4).each{ |n| is_expected.not_to be_match(version, n) }
134
+ end
135
+ end
136
+
137
+ context 'for different major version' do
138
+ let(:version){ v('ruby-2.7.7') }
139
+
140
+ it 'matches with 0 parts' do
141
+ is_expected.to be_match(version, 0)
142
+ end
143
+
144
+ it 'does not match with more parts' do
145
+ (1..4).each{ |n| is_expected.not_to be_match(version, n) }
146
+ end
147
+ end
148
+
149
+ context 'for version with additional part' do
150
+ let(:version){ v('ruby-1.7.7.1') }
151
+
152
+ it 'matches with 0..3 parts' do
153
+ (0..3).each{ |n| is_expected.to be_match(version, n) }
154
+ end
155
+
156
+ it 'does not match with more parts' do
157
+ is_expected.not_to be_match(version, 4)
158
+ end
159
+ end
160
+
161
+ context 'for pre release of same version' do
162
+ let(:version){ v('ruby-1.7.7-pre1') }
163
+
164
+ it 'matches with any number of parts' do
165
+ (0..4).each{ |n| is_expected.to be_match(version, n) }
166
+ end
167
+ end
168
+
169
+ context 'for different type of same version' do
170
+ let(:version){ v('jruby-1.7.7') }
171
+
172
+ it 'does not match' do
173
+ (0..4).each{ |n| is_expected.not_to be_match(version, n) }
174
+ end
175
+ end
176
+
177
+ context 'for different variant of same version' do
178
+ let(:version){ v('ruby-1.7.7-clang') }
179
+
180
+ it 'does not match' do
181
+ (0..4).each{ |n| is_expected.not_to be_match(version, n) }
182
+ end
183
+ end
184
+
185
+ context 'for version without version parts' do
186
+ let(:version){ v('ruby') }
187
+
188
+ it 'does not match' do
189
+ (0..4).each{ |n| is_expected.not_to be_match(version, n) }
190
+ end
191
+ end
192
+ end
193
+
194
+ describe '#inspect' do
195
+ {
196
+ '1.2.3-pre1' => '#<TravisCheckRubies::Version 1.2.3-pre1>',
197
+ 'jruby' => '#<TravisCheckRubies::Version jruby>',
198
+ }.each do |version_string, inspect|
199
+ context "for #{version_string}" do
200
+ it{ expect(v(version_string).inspect).to eq(inspect) }
201
+ end
202
+ end
203
+ end
204
+
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('http://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('http://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
+ allow(cache_path).to receive(:size?).and_return(616)
229
+ allow(cache_path).to receive(:mtime).and_return(Time.now - described_class::CACHE_TIME / 2)
230
+ allow(cache_path).to receive(:read).and_return("foo\nbar")
231
+
232
+ expect(Net::HTTP).not_to receive(:get)
233
+ expect(described_class.send(:index_urls)).to eq(%w[foo bar])
234
+ end
235
+
236
+ it 'writes cache file if it is stale' do
237
+ allow(cache_path).to receive(:size?).and_return(616)
238
+ allow(cache_path).to receive(:mtime).and_return(Time.now - described_class::CACHE_TIME * 2)
239
+ allow(Net::HTTP).to receive(:get).with(URI('http://rubies.travis-ci.org/index.txt')).
240
+ once.and_return("brave\nnew\nworld")
241
+
242
+ expect(described_class.send(:index_urls)).to eq(%w[brave new world])
243
+ expect(cache_path.read).to eq("brave\nnew\nworld")
244
+ end
245
+ end
246
+
247
+ describe '.base_url' do
248
+ before do
249
+ cleanup_instance_variables(described_class)
250
+ allow(ENV).to receive(:[]).with('TRAVIS').and_return(env_travis)
251
+ end
252
+
253
+ context 'when env variable TRAVIS is set' do
254
+ let(:env_travis){ 'true' }
255
+
256
+ it 'gets base_url from rvm debug' do
257
+ allow(described_class).to receive(:`).with('rvm debug').
258
+ and_return(%Q{ foo: "xxx" \n system: "XXX/YYY" \n bar: "yyy" })
259
+
260
+ expect(described_class.send(:base_url)).to eq('http://rubies.travis-ci.org/XXX/YYY/')
261
+ end
262
+ end
263
+
264
+ context 'when env variable TRAVIS is not set' do
265
+ let(:env_travis){ nil }
266
+
267
+ it 'gets base_url from first ubuntu url in index' do
268
+ allow(described_class).to receive(:index_urls).and_return(%w[
269
+ http://rubies.travis-ci.org/osx/AAA/1.tar.gz
270
+ http://rubies.travis-ci.org/ubuntu/ZZZ/2.tar.gz
271
+ http://rubies.travis-ci.org/ubuntu/BBB/3.tar.gz
272
+ ])
273
+
274
+ expect(described_class.send(:base_url)).to eq('http://rubies.travis-ci.org/ubuntu/BBB/')
275
+ end
276
+ end
277
+ end
278
+
279
+ describe '.available' do
280
+ before do
281
+ cleanup_instance_variables(described_class)
282
+ end
283
+
284
+ it 'gets sorted versions from index urls matching base_url' do
285
+ allow(described_class).to receive(:index_urls).and_return(%w[
286
+ http://rubies.travis-ci.org/osx/AAA/1.tar.gz
287
+ http://rubies.travis-ci.org/ubuntu/ZZZ/2.tar.gz
288
+ http://rubies.travis-ci.org/ubuntu/BBB/4.tar.gz
289
+ http://rubies.travis-ci.org/ubuntu/BBB/3.tar.bz2
290
+ ])
291
+ allow(described_class).to receive(:base_url).and_return('http://rubies.travis-ci.org/ubuntu/BBB/')
292
+
293
+ expect(described_class.available).to eq([v('3'), v('4')])
294
+ end
295
+
296
+ it 'caches result' do
297
+ allow(described_class).to receive(:index_urls).once.and_return(%w[
298
+ http://rubies.travis-ci.org/ubuntu/CCC/a.tar.gz
299
+ http://rubies.travis-ci.org/ubuntu/CCC/b.tar.bz2
300
+ ])
301
+ allow(described_class).to receive(:base_url).and_return('http://rubies.travis-ci.org/ubuntu/CCC/')
302
+
303
+ 3.times{ expect(described_class.available).to eq([v('a'), v('b')]) }
304
+ end
305
+ end
306
+
307
+ describe '.update' do
308
+ before do
309
+ allow(described_class).to receive(:available).and_return(vs(available_strs).sort)
310
+ end
311
+
312
+ context 'for version without version parts' do
313
+ let(:available_strs){ %w[ruby 1.2.3 2.3.4] }
314
+
315
+ it{ expect(described_class.update(v('ruby'))).to eq nil }
316
+ end
317
+
318
+ context 'when there are no updates' do
319
+ let(:available_strs){ %w[ruby 1.2.3 2.3.4] }
320
+
321
+ it{ expect(described_class.update(v('2.3.4'))).to eq nil }
322
+ end
323
+
324
+ context 'when version is not present' do
325
+ let(:available_strs){ %w[ruby 1.2.3 2.3.4] }
326
+
327
+ it{ expect(described_class.update(v('3.4.5'))).to eq [] }
328
+ end
329
+
330
+ describe 'parts and intermediary' do
331
+ let(:version){ v('1.7.1') }
332
+
333
+ let(:available_strs){ %w[
334
+ 1.7.1 1.7.2 1.8.6 1.8.7 1.9.2 1.9.3
335
+ 2.0.8 2.0.9 2.1.6 2.1.7 2.2.4 2.2.5
336
+ 3.0.4 3.0.5 3.1.2 3.1.3 3.2.0 3.2.1
337
+ ] }
338
+
339
+ context 'when intermediary is true' do
340
+ it 'returns all latest with distinct 0..2 (by default) matching version parts' do
341
+ expect(described_class.update(version)).to eq vs(%w[1.7.2 1.8.7 1.9.3 2.0.9 2.1.7 2.2.5 3.0.5 3.1.3 3.2.1])
342
+ end
343
+
344
+ {
345
+ 0 => %w[3.2.1],
346
+ 0..1 => %w[1.9.3 2.2.5 3.2.1],
347
+ 0..2 => %w[1.7.2 1.8.7 1.9.3 2.0.9 2.1.7 2.2.5 3.0.5 3.1.3 3.2.1],
348
+ 1..2 => %w[1.7.2 1.8.7 1.9.3],
349
+ 2 => %w[1.7.2],
350
+ }.each do |parts, expected|
351
+ it "returns all latest with distinct #{parts} matching version parts" do
352
+ expect(described_class.update(version, parts: parts)).to eq vs(expected)
353
+ end
354
+ end
355
+ end
356
+
357
+ context 'when intermediary is false' do
358
+ it 'returns latest for each 0..2 (by default) matching version parts' do
359
+ expect(described_class.update(version, intermediary: false)).to eq vs(%w[1.7.2 1.9.3 3.2.1])
360
+ end
361
+
362
+ {
363
+ 0 => %w[3.2.1],
364
+ 0..1 => %w[1.9.3 3.2.1],
365
+ 0..2 => %w[1.7.2 1.9.3 3.2.1],
366
+ 1..2 => %w[1.7.2 1.9.3],
367
+ 2 => %w[1.7.2],
368
+ }.each do |parts, expected|
369
+ it "returns latest for each #{parts} matching version parts" do
370
+ expect(described_class.update(version, parts: parts, intermediary: false)).to eq vs(expected)
371
+ end
372
+ end
373
+ end
374
+ end
375
+
376
+ describe 'pre releases' do
377
+ let(:available_strs){ %w[2.4.0-pre 2.4.0 2.4.1 2.4.2-pre1 2.4.2-pre2] }
378
+
379
+ context 'when for pre release there is only newer pre release' do
380
+ it 'returns next pre release' do
381
+ expect(described_class.update(v('2.4.2-pre1'))).to eq [v('2.4.2-pre2')]
382
+ end
383
+ end
384
+
385
+ context 'when there is a newer release and even newer pre release' do
386
+ context 'for release' do
387
+ it 'returns newer release when allow_pre is false' do
388
+ expect(described_class.update(v('2.4.0'))).to eq [v('2.4.1')]
389
+ end
390
+
391
+ it 'returns even newer pre release when allow_pre is true' do
392
+ expect(described_class.update(v('2.4.0'), allow_pre: true)).to eq [v('2.4.2-pre2')]
393
+ end
394
+ end
395
+
396
+ context 'for pre release' do
397
+ it 'returns release when allow_pre is false' do
398
+ expect(described_class.update(v('2.4.0-pre'))).to eq [v('2.4.1')]
399
+ end
400
+
401
+ it 'returns even newer pre release when allow_pre is true' do
402
+ expect(described_class.update(v('2.4.0-pre'), allow_pre: true)).to eq [v('2.4.2-pre2')]
403
+ end
404
+ end
405
+ end
406
+ end
407
+ end
408
+
409
+ describe '.updates' do
410
+ before do
411
+ allow(described_class).to receive(:available).
412
+ and_return(vs(%w[1.8.7 1.9.3 2.0.9 2.1.7]).sort)
413
+ end
414
+
415
+ it 'returns a hash with updates for higher versions removed from updates for lower versions' do
416
+ expect(described_class.updates(vs(%w[2.0.8 2.1.7 1.8.6 1.9.3])).to_a).
417
+ to eq({
418
+ v('2.0.8') => vs(%w[2.0.9]),
419
+ v('2.1.7') => nil,
420
+ v('1.8.6') => vs(%w[1.8.7]),
421
+ v('1.9.3') => nil,
422
+ }.to_a)
423
+ end
424
+ end
425
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'travis_check_rubies'
5
- s.version = '0.1.0'
5
+ s.version = '0.2.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 http://rubies.travis-ci.org and propose changes'
8
8
  s.homepage = "http://github.com/toy/#{s.name}"
@@ -13,4 +13,10 @@ Gem::Specification.new do |s|
13
13
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
14
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
15
  s.require_paths = %w[lib]
16
+
17
+ s.required_ruby_version = '>= 2.0.0'
18
+
19
+ s.add_runtime_dependency 'fspath', '~> 3.0'
20
+
21
+ s.add_development_dependency 'rspec', '~> 3.0'
16
22
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: travis_check_rubies
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Kuchin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-22 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2017-03-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fspath
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
13
41
  description: Check if `.travis.yml` specifies latest available rubies from listed
14
42
  on http://rubies.travis-ci.org and propose changes
15
43
  email:
@@ -18,14 +46,16 @@ executables:
18
46
  extensions: []
19
47
  extra_rdoc_files: []
20
48
  files:
21
- - .gitignore
22
- - .travis.yml
49
+ - ".gitignore"
50
+ - ".travis.yml"
23
51
  - Gemfile
24
52
  - LICENSE.txt
25
53
  - README.markdown
26
54
  - bin/travis_check_rubies
27
55
  - lib/travis_check_rubies.rb
56
+ - lib/travis_check_rubies/travis_yml.rb
28
57
  - lib/travis_check_rubies/version.rb
58
+ - spec/travis_check_rubies/version_spec.rb
29
59
  - travis_check_rubies.gemspec
30
60
  homepage: http://github.com/toy/travis_check_rubies
31
61
  licenses:
@@ -37,19 +67,19 @@ require_paths:
37
67
  - lib
38
68
  required_ruby_version: !ruby/object:Gem::Requirement
39
69
  requirements:
40
- - - ! '>='
70
+ - - ">="
41
71
  - !ruby/object:Gem::Version
42
- version: '0'
72
+ version: 2.0.0
43
73
  required_rubygems_version: !ruby/object:Gem::Requirement
44
74
  requirements:
45
- - - ! '>='
75
+ - - ">="
46
76
  - !ruby/object:Gem::Version
47
77
  version: '0'
48
78
  requirements: []
49
79
  rubyforge_project:
50
- rubygems_version: 2.6.4
80
+ rubygems_version: 2.6.10
51
81
  signing_key:
52
82
  specification_version: 4
53
83
  summary: Are you using the latest rubies in .travis.yml?
54
- test_files: []
55
- has_rdoc:
84
+ test_files:
85
+ - spec/travis_check_rubies/version_spec.rb