libyear-bundler 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 734b3af6eedfa8bd832666a33e04ccf4d36dbcec
4
- data.tar.gz: 70d4f09011a3102403bec195b4638d7dbbbc73d8
3
+ metadata.gz: 2bc00352e31430c9a27e420073d5284a343a840a
4
+ data.tar.gz: 10d60b3b473df24f7a7a6140a22d4ed8bfe7f8a8
5
5
  SHA512:
6
- metadata.gz: cb0e53a70abcd38aba307d8ea2dac3ffbace0192cd26a8f2b2de960a42c36e6aa4fbae86d951dbfa9eab27796dddbd73d10e8fa7fbfb952dc3e3795bcc595e61
7
- data.tar.gz: 65b896dcdbbbc1feea606390b5a20b54680c95e8feb763989a651d1e646f11c2799d83c0e7c54c9c40ca1d464d67fcec3932eb15c2e058b08ad30384d28d8a31
6
+ metadata.gz: ec414ad1bb5b06517e6fa39fd7ebf1265a8ea42c36f1a9bf225d16bac46fcb61df3f97506725204bd3563b5425f02e28ff5e847bbfbdf8fcc0eaf1a06373be92
7
+ data.tar.gz: 0e3f53fc0fa0a497abd545e4e91eaa1d82e399d54401cf982393c6db3ff3b28c248a20f4e9d68e8b08d68d3f27e6b4daff1e88ac9bb7e5e82c240eb00d8d2ca9
@@ -0,0 +1,11 @@
1
+ Metrics/AbcSize:
2
+ Max: 27
3
+
4
+ Metrics/LineLength:
5
+ Max: 100
6
+
7
+ Metrics/MethodLength:
8
+ Enabled: false
9
+
10
+ Style/StringLiterals:
11
+ Enabled: false
@@ -17,6 +17,21 @@ Fixed:
17
17
 
18
18
  - None
19
19
 
20
+ ## 0.4.0 (2017-07-07)
21
+
22
+ Breaking changes:
23
+
24
+ - None
25
+
26
+ Added:
27
+
28
+ - [#3](https://github.com/jaredbeck/libyear-bundler/pull/3)
29
+ Add --versions and --releases
30
+
31
+ Fixed:
32
+
33
+ - None
34
+
20
35
  ## 0.3.0 (2017-03-24)
21
36
 
22
37
  Breaking changes:
data/asd ADDED
File without changes
@@ -0,0 +1,50 @@
1
+ module Calculators
2
+ # A libyear is the difference in time between releases of the newest and
3
+ # installed versions of the gem in years
4
+ class Libyear
5
+ class << self
6
+ def calculate(gem)
7
+ di = release_date(gem[:name], gem[:installed][:version])
8
+ dn = release_date(gem[:name], gem[:newest][:version])
9
+ gem[:installed][:date] = di
10
+ gem[:newest][:date] = dn
11
+ if di.nil? || dn.nil? || dn <= di
12
+ # Known issue: Backports and maintenance releases of older minor versions.
13
+ # Example: json 1.8.6 (2017-01-13) was released *after* 2.0.3 (2017-01-12)
14
+ years = 0.0
15
+ else
16
+ days = (dn - di).to_f
17
+ years = days / 365.0
18
+ end
19
+ years
20
+ end
21
+
22
+ private
23
+
24
+ # Known issue: Probably performs a network request every time, unless
25
+ # there's some kind of caching.
26
+ def release_date(gem_name, gem_version)
27
+ dep = nil
28
+ begin
29
+ dep = ::Bundler::Dependency.new(gem_name, gem_version)
30
+ rescue ::Gem::Requirement::BadRequirementError => e
31
+ $stderr.puts "Could not find release date for: #{gem_name}"
32
+ $stderr.puts(e)
33
+ $stderr.puts(
34
+ "Maybe you used git in your Gemfile, which libyear doesn't support " \
35
+ "yet. Contributions welcome."
36
+ )
37
+ return nil
38
+ end
39
+ tuples, _errors = ::Gem::SpecFetcher.fetcher.search_for_dependency(dep)
40
+ if tuples.empty?
41
+ $stderr.puts "Could not find release date for: #{gem_name}"
42
+ return nil
43
+ end
44
+ tup, source = tuples.first # Gem::NameTuple
45
+ spec = source.fetch_spec(tup) # raises Gem::RemoteFetcher::FetchError
46
+ spec.date.to_date
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,44 @@
1
+ module Calculators
2
+ # The version number delta is the absolute difference between the highest-
3
+ # order version number of the installed and newest releases
4
+ class VersionNumberDelta
5
+ class << self
6
+ def calculate(gem)
7
+ newest_version_tuple = version_tuple(gem[:newest][:version].split('.'))
8
+ installed_version_tuple = version_tuple(gem[:installed][:version].split('.'))
9
+ major_version_delta = version_delta(
10
+ newest_version_tuple.major, installed_version_tuple.major
11
+ )
12
+ minor_version_delta = version_delta(
13
+ newest_version_tuple.minor, installed_version_tuple.minor
14
+ )
15
+ patch_version_delta = version_delta(
16
+ newest_version_tuple.patch, installed_version_tuple.patch
17
+ )
18
+ highest_order([major_version_delta, minor_version_delta, patch_version_delta])
19
+ end
20
+
21
+ private
22
+
23
+ def highest_order(arr)
24
+ arr[1] = arr[2] = 0 if arr[0] > 0
25
+ arr[2] = 0 if arr[1] > 0
26
+ arr
27
+ end
28
+
29
+ def version_delta(newest_version, installed_version)
30
+ delta = newest_version - installed_version
31
+ delta < 0 ? 0 : delta
32
+ end
33
+
34
+ def version_tuple(version_array)
35
+ version_struct = Struct.new(:major, :minor, :patch)
36
+ version_struct.new(
37
+ version_array[0].to_i,
38
+ version_array[1].to_i,
39
+ version_array[2].to_i
40
+ )
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,20 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'json'
4
+
5
+ module Calculators
6
+ # The version sequence delta is the number of releases between the newest and
7
+ # installed versions of the gem
8
+ class VersionSequenceDelta
9
+ class << self
10
+ def calculate(gem)
11
+ uri = URI.parse("https://rubygems.org/api/v1/versions/#{gem[:name]}.json")
12
+ response = Net::HTTP.get_response(uri)
13
+ versions = JSON.parse(response.body).map { |version| version["number"] }
14
+ newest_seq = versions.index(gem[:newest][:version])
15
+ installed_seq = versions.index(gem[:installed][:version])
16
+ installed_seq - newest_seq
17
+ end
18
+ end
19
+ end
20
+ end
@@ -4,10 +4,15 @@ require "libyear_bundler/report"
4
4
  require "libyear_bundler/query"
5
5
 
6
6
  module LibyearBundler
7
+ # The `libyear-bundler` command line program
7
8
  class CLI
8
- OPTIONS = %w(
9
+ OPTIONS = %w[
10
+ --all
9
11
  --grand-total
10
- ).freeze
12
+ --libyears
13
+ --releases
14
+ --versions
15
+ ].freeze
11
16
 
12
17
  E_BUNDLE_OUTDATED_FAILED = 1
13
18
  E_NO_GEMFILE = 2
@@ -22,7 +27,7 @@ module LibyearBundler
22
27
  if @argv.include?("--grand-total")
23
28
  grand_total
24
29
  else
25
- print Report.new(query).to_s
30
+ print report.to_s
26
31
  end
27
32
  end
28
33
 
@@ -51,7 +56,11 @@ module LibyearBundler
51
56
  end
52
57
 
53
58
  def query
54
- Query.new(@gemfile_path).execute
59
+ Query.new(@gemfile_path, @argv).execute
60
+ end
61
+
62
+ def report
63
+ @_report ||= Report.new(query)
55
64
  end
56
65
 
57
66
  def unexpected_options
@@ -64,16 +73,46 @@ module LibyearBundler
64
73
  end
65
74
 
66
75
  def validate_arguments
67
- unless unexpected_options.empty?
68
- puts "Unexpected args: #{unexpected_options.join(", ")}"
69
- puts "Allowed args: #{OPTIONS.join(", ")}"
70
- exit E_NO_GEMFILE
71
- end
76
+ return if unexpected_options.empty?
77
+ puts "Unexpected args: #{unexpected_options.join(', ')}"
78
+ puts "Allowed args: #{OPTIONS.join(', ')}"
79
+ exit E_NO_GEMFILE
72
80
  end
73
81
 
74
82
  def grand_total
75
- sum_years = query.map { |gem| gem[:libyears] }.inject(0.0, :+)
76
- puts format("%.1f", sum_years)
83
+ puts calculate_grand_total
84
+ end
85
+
86
+ def calculate_grand_total
87
+ if report.to_h.key?(:sum_seq_delta) && report.to_h.key?(:sum_major_version)
88
+ [
89
+ libyears_grand_total,
90
+ releases_grand_total,
91
+ versions_grand_total
92
+ ].join("\n")
93
+ elsif report.to_h.key?(:sum_seq_delta)
94
+ releases_grand_total
95
+ elsif report.to_h.key?(:sum_major_version)
96
+ versions_grand_total
97
+ else
98
+ libyears_grand_total
99
+ end
100
+ end
101
+
102
+ def libyears_grand_total
103
+ report.to_h[:sum_years].truncate(1)
104
+ end
105
+
106
+ def releases_grand_total
107
+ report.to_h[:sum_seq_delta]
108
+ end
109
+
110
+ def versions_grand_total
111
+ [
112
+ report.to_h[:sum_major_version],
113
+ report.to_h[:sum_minor_version],
114
+ report.to_h[:sum_patch_version]
115
+ ].to_s
77
116
  end
78
117
  end
79
118
  end
@@ -1,5 +1,8 @@
1
1
  require "English"
2
2
  require "open3"
3
+ require 'libyear_bundler/calculators/libyear'
4
+ require 'libyear_bundler/calculators/version_number_delta'
5
+ require 'libyear_bundler/calculators/version_sequence_delta'
3
6
 
4
7
  module LibyearBundler
5
8
  # Responsible for getting all the data that goes into the `Report`.
@@ -7,8 +10,9 @@ module LibyearBundler
7
10
  # Format of `bundle outdated --parseable` (BOP)
8
11
  BOP_FMT = /\A(?<name>[^ ]+) \(newest (?<newest>[^,]+), installed (?<installed>[^,)]+)/
9
12
 
10
- def initialize(gemfile_path)
13
+ def initialize(gemfile_path, argv)
11
14
  @gemfile_path = gemfile_path
15
+ @argv = argv
12
16
  end
13
17
 
14
18
  def execute
@@ -23,19 +27,15 @@ module LibyearBundler
23
27
  )
24
28
  end
25
29
  gems.each do |gem|
26
- di = release_date(gem[:name], gem[:installed][:version])
27
- dn = release_date(gem[:name], gem[:newest][:version])
28
- gem[:installed][:date] = di
29
- gem[:newest][:date] = dn
30
- if di.nil? || dn.nil? || dn <= di
31
- # Known issue: Backports and maintenance releases of older minor versions.
32
- # Example: json 1.8.6 (2017-01-13) was released *after* 2.0.3 (2017-01-12)
33
- years = 0.0
34
- else
35
- days = (dn - di).to_f
36
- years = days / 365.0
30
+ if @argv.include?("--versions") || @argv.include?("--all")
31
+ gem[:version_number_delta] = ::Calculators::VersionNumberDelta.calculate(gem)
37
32
  end
38
- gem[:libyears] = years
33
+
34
+ if @argv.include?("--releases") || @argv.include?("--all")
35
+ gem[:version_sequence_delta] = ::Calculators::VersionSequenceDelta.calculate(gem)
36
+ end
37
+
38
+ gem[:libyears] = ::Calculators::Libyear.calculate(gem)
39
39
  end
40
40
  gems
41
41
  end
@@ -44,7 +44,7 @@ module LibyearBundler
44
44
 
45
45
  def bundle_outdated
46
46
  stdout, stderr, status = Open3.capture3(
47
- %Q(BUNDLE_GEMFILE="#{@gemfile_path}" bundle outdated --parseable)
47
+ %(BUNDLE_GEMFILE="#{@gemfile_path}" bundle outdated --parseable)
48
48
  )
49
49
  # Known statuses:
50
50
  # 0 - Nothing is outdated
@@ -59,30 +59,5 @@ module LibyearBundler
59
59
  end
60
60
  stdout
61
61
  end
62
-
63
- # Known issue: Probably performs a network request every time, unless
64
- # there's some kind of caching.
65
- def release_date(gem_name, gem_version)
66
- dep = nil
67
- begin
68
- dep = ::Bundler::Dependency.new(gem_name, gem_version)
69
- rescue ::Gem::Requirement::BadRequirementError => e
70
- $stderr.puts "Could not find release date for: #{gem_name}"
71
- $stderr.puts(e)
72
- $stderr.puts(
73
- "Maybe you used git in your Gemfile, which libyear doesn't support " \
74
- "yet. Contributions welcome."
75
- )
76
- return nil
77
- end
78
- tuples, _errors = ::Gem::SpecFetcher.fetcher.search_for_dependency(dep)
79
- if tuples.empty?
80
- $stderr.puts "Could not find release date for: #{gem_name}"
81
- return nil
82
- end
83
- tup, source = tuples.first # Gem::NameTuple
84
- spec = source.fetch_spec(tup) # raises Gem::RemoteFetcher::FetchError
85
- spec.date.to_date
86
- end
87
62
  end
88
63
  end
@@ -2,29 +2,115 @@ module LibyearBundler
2
2
  # Responsible presenting data from the `Query`. Should only be concerned
3
3
  # with presentation, nothing else.
4
4
  class Report
5
+ FMT_RELEASES_COLUMN = "%10d".freeze
6
+ FMT_VERSIONS_COLUMN = "%15s".freeze
7
+
5
8
  # `gems` - Array of hashes.
6
9
  def initialize(gems)
7
10
  @gems = gems
8
11
  end
9
12
 
10
13
  def to_s
11
- sum_years = 0.0
12
- @gems.each do |gem|
13
- years = gem[:libyears]
14
- sum_years += years
15
- puts(
16
- format(
17
- "%30s%15s%15s%15s%15s%10.1f",
18
- gem[:name],
19
- gem[:installed][:version],
20
- gem[:installed][:date],
21
- gem[:newest][:version],
22
- gem[:newest][:date],
23
- years
24
- )
25
- )
14
+ to_h[:gems].each { |gem| put_gem_summary(gem) }
15
+ put_summary(to_h)
16
+ end
17
+
18
+ def to_h
19
+ @_to_h ||=
20
+ begin
21
+ summary = {
22
+ gems: @gems,
23
+ sum_years: 0.0
24
+ }
25
+ @gems.each_with_object(summary) do |gem, memo|
26
+ memo[:sum_years] += gem[:libyears]
27
+
28
+ if gem.key?(:version_number_delta)
29
+ memo[:sum_major_version] ||= 0
30
+ memo[:sum_major_version] += gem[:version_number_delta][0]
31
+ memo[:sum_minor_version] ||= 0
32
+ memo[:sum_minor_version] += gem[:version_number_delta][1]
33
+ memo[:sum_patch_version] ||= 0
34
+ memo[:sum_patch_version] += gem[:version_number_delta][2]
35
+ end
36
+
37
+ if gem.key?(:version_sequence_delta)
38
+ memo[:sum_seq_delta] ||= 0
39
+ memo[:sum_seq_delta] += gem[:version_sequence_delta]
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def put_gem_summary(gem)
48
+ meta = meta_gem_summary(gem)
49
+ libyear = format("%10.1f", gem[:libyears])
50
+
51
+ if gem.key?(:version_sequence_delta) && gem.key?(:version_number_delta)
52
+ releases = format(FMT_RELEASES_COLUMN, gem[:version_sequence_delta])
53
+ versions = format(FMT_VERSIONS_COLUMN, gem[:version_number_delta])
54
+ puts meta << libyear << releases << versions
55
+ elsif gem.key?(:version_sequence_delta)
56
+ releases = format(FMT_RELEASES_COLUMN, gem[:version_sequence_delta])
57
+ puts meta << releases
58
+ elsif gem.key?(:version_number_delta)
59
+ versions = format(FMT_VERSIONS_COLUMN, gem[:version_number_delta])
60
+ puts meta << versions
61
+ else
62
+ puts meta << libyear
26
63
  end
64
+ end
65
+
66
+ def meta_gem_summary(gem)
67
+ format(
68
+ "%30s%15s%15s%15s%15s",
69
+ gem[:name],
70
+ gem[:installed][:version],
71
+ gem[:installed][:date],
72
+ gem[:newest][:version],
73
+ gem[:newest][:date]
74
+ )
75
+ end
76
+
77
+ def put_libyear_summary(sum_years)
27
78
  puts format("System is %.1f libyears behind", sum_years)
28
79
  end
80
+
81
+ def put_version_delta_summary(sum_major_version, sum_minor_version, sum_patch_version)
82
+ puts format(
83
+ "Major, minor, patch versions behind: %d, %d, %d",
84
+ sum_major_version,
85
+ sum_minor_version,
86
+ sum_patch_version
87
+ )
88
+ end
89
+
90
+ def put_sum_seq_delta_summary(sum_seq_delta)
91
+ puts format("Total releases behind: %d", sum_seq_delta)
92
+ end
93
+
94
+ def put_summary(summary)
95
+ if summary.key?(:sum_seq_delta) && summary.key?(:sum_major_version)
96
+ put_libyear_summary(summary[:sum_years])
97
+ put_sum_seq_delta_summary(summary[:sum_seq_delta])
98
+ put_version_delta_summary(
99
+ summary[:sum_major_version],
100
+ summary[:sum_minor_version],
101
+ summary[:sum_patch_version]
102
+ )
103
+ elsif summary.key?(:sum_major_version)
104
+ put_version_delta_summary(
105
+ summary[:sum_major_version],
106
+ summary[:sum_minor_version],
107
+ summary[:sum_patch_version]
108
+ )
109
+ elsif summary.key?(:sum_seq_delta)
110
+ put_sum_seq_delta_summary(summary[:sum_seq_delta])
111
+ else
112
+ put_libyear_summary(summary[:sum_years])
113
+ end
114
+ end
29
115
  end
30
116
  end
@@ -1,3 +1,3 @@
1
1
  module LibyearBundler
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0".freeze
3
3
  end
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+
2
3
  lib = File.expand_path('../lib', __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'libyear_bundler/version'
@@ -19,4 +20,5 @@ Gem::Specification.new do |spec|
19
20
  spec.require_paths = ["lib"]
20
21
  spec.required_ruby_version = ">= 2.1"
21
22
  spec.add_dependency "bundler", "~> 1.14"
23
+ spec.add_development_dependency "rubocop"
22
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libyear-bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jared Beck
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-24 00:00:00.000000000 Z
11
+ date: 2017-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  description:
28
42
  email:
29
43
  - jared@jaredbeck.com
@@ -33,12 +47,17 @@ extensions: []
33
47
  extra_rdoc_files: []
34
48
  files:
35
49
  - ".gitignore"
50
+ - ".rubocop.yml"
36
51
  - CHANGELOG.md
37
52
  - Gemfile
38
53
  - LICENSE.txt
39
54
  - README.md
55
+ - asd
40
56
  - bin/libyear-bundler
41
57
  - lib/libyear_bundler.rb
58
+ - lib/libyear_bundler/calculators/libyear.rb
59
+ - lib/libyear_bundler/calculators/version_number_delta.rb
60
+ - lib/libyear_bundler/calculators/version_sequence_delta.rb
42
61
  - lib/libyear_bundler/cli.rb
43
62
  - lib/libyear_bundler/query.rb
44
63
  - lib/libyear_bundler/report.rb
@@ -64,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
83
  version: '0'
65
84
  requirements: []
66
85
  rubyforge_project:
67
- rubygems_version: 2.6.11
86
+ rubygems_version: 2.6.12
68
87
  signing_key:
69
88
  specification_version: 4
70
89
  summary: A simple measure of dependency freshness