bundle_update_interactive 0.5.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -0
- data/lib/bundle_update_interactive/bundler_commands.rb +8 -0
- data/lib/bundle_update_interactive/cli/multi_select.rb +35 -17
- data/lib/bundle_update_interactive/cli/row.rb +4 -11
- data/lib/bundle_update_interactive/cli/table.rb +36 -4
- data/lib/bundle_update_interactive/cli.rb +20 -13
- data/lib/bundle_update_interactive/outdated_gem.rb +2 -1
- data/lib/bundle_update_interactive/report.rb +10 -41
- data/lib/bundle_update_interactive/reporter.rb +66 -0
- data/lib/bundle_update_interactive/semver_change.rb +3 -1
- data/lib/bundle_update_interactive/version.rb +1 -1
- data/lib/bundle_update_interactive.rb +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58fa0e12f3322d018b1fcaa788dd3b8a2c3354042fe1e6ab21313d0bc0d7518b
|
4
|
+
data.tar.gz: a43866c8bad9bc0256b369cbf7e29db56c2b06293f2ae3a4a3e560ff75506e16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5325810c277c4a3f58d3308b9899c9097a2c723996e79030ccda96f79408c83734b2bcf9ae5920a1ee74f32837ebae91f4e946aa9ff08225db73bf6d06d69e91
|
7
|
+
data.tar.gz: d241d58cb408a0b6294a8b56e010b8ffa841bdbb5ccf28c794fb2db4ebcc562f7ec486742ec36720ed9522c9cf2ce1d27d8a68619fefbee59d28810b3044e7fb
|
data/README.md
CHANGED
@@ -63,6 +63,12 @@ Some gems, notably `rails`, are composed of smaller gems like `actionpack`, `act
|
|
63
63
|
|
64
64
|
Therefore, if any Rails component has a security vulnerability, `bundle update-interactive` will automatically roll up that information into a single `rails` line item, so you can select it and upgrade all of its components in one shot.
|
65
65
|
|
66
|
+
### Held back gems
|
67
|
+
|
68
|
+
When a newer version of a gem is available, but updating is not allowed due to a Gemfile requirement, `update-interactive` will report that the gem has been held back.
|
69
|
+
|
70
|
+
<img src="images/held-back.png" alt="Screenshot of rails and selenium-webdriver gems held back due to Gemfile requirements" width="717" />
|
71
|
+
|
66
72
|
### Changelogs
|
67
73
|
|
68
74
|
`bundle update-interactive` will do its best to find an appropriate changelog for each gem.
|
@@ -19,6 +19,14 @@ module BundleUpdateInteractive
|
|
19
19
|
`#{command.join(" ")}`.tap { raise "bundle lock command failed" unless Process.last_status.success? }
|
20
20
|
end
|
21
21
|
|
22
|
+
def parse_outdated(*gems)
|
23
|
+
command = ["#{bundle_bin.shellescape} outdated --parseable", *gems.flatten.map(&:shellescape)]
|
24
|
+
output = `#{command.join(" ")}`
|
25
|
+
raise "bundle outdated command failed" if output.empty? && !Process.last_status.success?
|
26
|
+
|
27
|
+
output.scan(/^(\S+) \(newest (\S+),/).to_h
|
28
|
+
end
|
29
|
+
|
22
30
|
private
|
23
31
|
|
24
32
|
def bundle_bin
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "launchy"
|
3
4
|
require "pastel"
|
4
5
|
require "tty/prompt"
|
5
6
|
require "tty/screen"
|
@@ -8,6 +9,7 @@ class BundleUpdateInteractive::CLI
|
|
8
9
|
class MultiSelect
|
9
10
|
class List < TTY::Prompt::MultiList
|
10
11
|
def initialize(prompt, **options)
|
12
|
+
@opener = options.delete(:opener)
|
11
13
|
defaults = {
|
12
14
|
cycle: true,
|
13
15
|
help_color: :itself.to_proc,
|
@@ -21,48 +23,64 @@ class BundleUpdateInteractive::CLI
|
|
21
23
|
def selected_names
|
22
24
|
""
|
23
25
|
end
|
26
|
+
|
27
|
+
# Unregister tty-prompt's default ctrl-a and ctrl-r bindings
|
28
|
+
alias select_all keyctrl_a
|
29
|
+
alias reverse_selection keyctrl_r
|
30
|
+
def keyctrl_a(*); end
|
31
|
+
def keyctrl_r(*); end
|
32
|
+
|
33
|
+
def keypress(event)
|
34
|
+
case event.value
|
35
|
+
when "k", "p" then keyup
|
36
|
+
when "j", "n" then keydown
|
37
|
+
when "a" then select_all
|
38
|
+
when "r" then reverse_selection
|
39
|
+
when "o" then opener&.call(choices[@active - 1].value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
attr_reader :opener
|
24
46
|
end
|
25
47
|
|
26
|
-
def self.prompt_for_gems_to_update(outdated_gems)
|
27
|
-
table = Table.
|
48
|
+
def self.prompt_for_gems_to_update(outdated_gems, prompt: nil)
|
49
|
+
table = Table.updatable(outdated_gems)
|
28
50
|
title = "#{outdated_gems.length} gems can be updated."
|
29
|
-
|
51
|
+
opener = lambda do |gem|
|
52
|
+
url = outdated_gems[gem].changelog_uri
|
53
|
+
Launchy.open(url) unless url.nil?
|
54
|
+
end
|
55
|
+
chosen = new(title: title, table: table, prompt: prompt, opener: opener).prompt
|
30
56
|
outdated_gems.slice(*chosen)
|
31
57
|
end
|
32
58
|
|
33
|
-
def initialize(title:, table:)
|
59
|
+
def initialize(title:, table:, opener: nil, prompt: nil)
|
34
60
|
@title = title
|
35
61
|
@table = table
|
36
|
-
@
|
62
|
+
@opener = opener
|
63
|
+
@tty_prompt = prompt || TTY::Prompt.new(
|
37
64
|
interrupt: lambda {
|
38
65
|
puts
|
39
66
|
exit(130)
|
40
67
|
}
|
41
68
|
)
|
42
|
-
add_keybindings
|
43
|
-
|
44
69
|
@pastel = BundleUpdateInteractive.pastel
|
45
70
|
end
|
46
71
|
|
47
72
|
def prompt
|
48
73
|
choices = table.gem_names.to_h { |name| [table.render_gem(name), name] }
|
49
|
-
tty_prompt.invoke_select(List, title, choices, help: help)
|
74
|
+
tty_prompt.invoke_select(List, title, choices, help: help, opener: opener)
|
50
75
|
end
|
51
76
|
|
52
77
|
private
|
53
78
|
|
54
|
-
attr_reader :pastel, :table, :tty_prompt, :title
|
55
|
-
|
56
|
-
def add_keybindings
|
57
|
-
tty_prompt.on(:keypress) do |event|
|
58
|
-
tty_prompt.trigger(:keyup) if %w[k p].include?(event.value)
|
59
|
-
tty_prompt.trigger(:keydown) if %w[j n].include?(event.value)
|
60
|
-
end
|
61
|
-
end
|
79
|
+
attr_reader :pastel, :table, :opener, :tty_prompt, :title
|
62
80
|
|
63
81
|
def help
|
64
82
|
[
|
65
|
-
pastel.dim("\nPress <space> to select, ↑/↓ move, <
|
83
|
+
pastel.dim("\nPress <space> to select, ↑/↓ move, <a> all, <r> reverse, <o> open url, <enter> to finish."),
|
66
84
|
"\n ",
|
67
85
|
table.render_header
|
68
86
|
].join
|
@@ -16,17 +16,6 @@ class BundleUpdateInteractive::CLI
|
|
16
16
|
@pastel = BundleUpdateInteractive.pastel
|
17
17
|
end
|
18
18
|
|
19
|
-
def to_a
|
20
|
-
[
|
21
|
-
formatted_gem_name,
|
22
|
-
formatted_current_version,
|
23
|
-
"→",
|
24
|
-
formatted_updated_version,
|
25
|
-
formatted_gemfile_groups,
|
26
|
-
formatted_changelog_uri
|
27
|
-
]
|
28
|
-
end
|
29
|
-
|
30
19
|
def formatted_gem_name
|
31
20
|
vulnerable? ? pastel.white.on_red(name) : apply_semver_highlight(name)
|
32
21
|
end
|
@@ -46,6 +35,10 @@ class BundleUpdateInteractive::CLI
|
|
46
35
|
gemfile_groups&.map(&:inspect)&.join(", ")
|
47
36
|
end
|
48
37
|
|
38
|
+
def formatted_gemfile_requirement
|
39
|
+
gemfile_requirement.to_s == ">= 0" ? "" : gemfile_requirement.to_s
|
40
|
+
end
|
41
|
+
|
49
42
|
def formatted_changelog_uri
|
50
43
|
pastel.blue(changelog_uri)
|
51
44
|
end
|
@@ -4,12 +4,44 @@ require "pastel"
|
|
4
4
|
|
5
5
|
class BundleUpdateInteractive::CLI
|
6
6
|
class Table
|
7
|
-
|
7
|
+
class << self
|
8
|
+
def withheld(gems)
|
9
|
+
columns = [
|
10
|
+
["name", :formatted_gem_name],
|
11
|
+
["requirement", :formatted_gemfile_requirement],
|
12
|
+
["current", :formatted_current_version],
|
13
|
+
["latest", :formatted_updated_version],
|
14
|
+
["group", :formatted_gemfile_groups],
|
15
|
+
["url", :formatted_changelog_uri]
|
16
|
+
]
|
17
|
+
new(gems, columns)
|
18
|
+
end
|
8
19
|
|
9
|
-
|
20
|
+
def updatable(gems)
|
21
|
+
columns = [
|
22
|
+
["name", :formatted_gem_name],
|
23
|
+
["from", :formatted_current_version],
|
24
|
+
[nil, "→"],
|
25
|
+
["to", :formatted_updated_version],
|
26
|
+
["group", :formatted_gemfile_groups],
|
27
|
+
["url", :formatted_changelog_uri]
|
28
|
+
]
|
29
|
+
new(gems, columns)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(gems, columns)
|
10
34
|
@pastel = BundleUpdateInteractive.pastel
|
11
|
-
@headers =
|
12
|
-
@rows =
|
35
|
+
@headers = columns.map { |header, _| pastel.dim.underline(header) }
|
36
|
+
@rows = gems.transform_values do |gem|
|
37
|
+
row = Row.new(gem)
|
38
|
+
columns.map do |_, col|
|
39
|
+
case col
|
40
|
+
when Symbol then row.public_send(col).to_s
|
41
|
+
when String then col
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
13
45
|
@column_widths = calculate_column_widths
|
14
46
|
end
|
15
47
|
|
@@ -11,19 +11,16 @@ module BundleUpdateInteractive
|
|
11
11
|
|
12
12
|
def run(argv: ARGV) # rubocop:disable Metrics/AbcSize
|
13
13
|
options = Options.parse(argv)
|
14
|
-
|
15
14
|
report = generate_report(options)
|
16
|
-
puts("No gems to update.").then { return } if report.updateable_gems.empty?
|
17
15
|
|
18
|
-
|
19
|
-
puts
|
20
|
-
|
21
|
-
selected_gems = MultiSelect.prompt_for_gems_to_update(report.
|
16
|
+
puts_legend_and_withheld_gems(report) unless report.empty?
|
17
|
+
puts("No gems to update.").then { return } if report.updatable_gems.empty?
|
18
|
+
|
19
|
+
selected_gems = MultiSelect.prompt_for_gems_to_update(report.updatable_gems)
|
22
20
|
puts("No gems to update.").then { return } if selected_gems.empty?
|
23
21
|
|
24
|
-
puts "
|
25
|
-
puts
|
26
|
-
puts Table.new(selected_gems).render
|
22
|
+
puts "Updating the following gems."
|
23
|
+
puts Table.updatable(selected_gems).render
|
27
24
|
puts
|
28
25
|
report.bundle_update!(*selected_gems.keys)
|
29
26
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
@@ -32,6 +29,17 @@ module BundleUpdateInteractive
|
|
32
29
|
|
33
30
|
private
|
34
31
|
|
32
|
+
def puts_legend_and_withheld_gems(report)
|
33
|
+
puts
|
34
|
+
puts legend
|
35
|
+
puts
|
36
|
+
return if report.withheld_gems.empty?
|
37
|
+
|
38
|
+
puts "The following gems are being held back and cannot be updated."
|
39
|
+
puts Table.withheld(report.withheld_gems).render
|
40
|
+
puts
|
41
|
+
end
|
42
|
+
|
35
43
|
def legend
|
36
44
|
pastel = BundleUpdateInteractive.pastel
|
37
45
|
<<~LEGEND
|
@@ -46,14 +54,13 @@ module BundleUpdateInteractive
|
|
46
54
|
|
47
55
|
def generate_report(options)
|
48
56
|
whisper "Resolving latest gem versions..."
|
49
|
-
report =
|
50
|
-
|
51
|
-
return report if updateable_gems.empty?
|
57
|
+
report = Reporter.new(groups: options.exclusively).generate_report
|
58
|
+
return report if report.empty?
|
52
59
|
|
53
60
|
whisper "Checking for security vulnerabilities..."
|
54
61
|
report.scan_for_vulnerabilities!
|
55
62
|
|
56
|
-
progress "Finding changelogs",
|
63
|
+
progress "Finding changelogs", report.all_gems.values, &:changelog_uri
|
57
64
|
report
|
58
65
|
end
|
59
66
|
|
@@ -4,13 +4,14 @@ module BundleUpdateInteractive
|
|
4
4
|
class OutdatedGem
|
5
5
|
attr_accessor :name,
|
6
6
|
:gemfile_groups,
|
7
|
+
:gemfile_requirement,
|
7
8
|
:git_source_uri,
|
8
9
|
:current_version,
|
9
10
|
:current_git_version,
|
10
11
|
:updated_version,
|
11
12
|
:updated_git_version
|
12
13
|
|
13
|
-
attr_writer :rubygems_source, :vulnerable
|
14
|
+
attr_writer :changelog_uri, :rubygems_source, :vulnerable
|
14
15
|
|
15
16
|
def initialize(**attrs)
|
16
17
|
@vulnerable = nil
|
@@ -7,38 +7,20 @@ require "set"
|
|
7
7
|
|
8
8
|
module BundleUpdateInteractive
|
9
9
|
class Report
|
10
|
-
|
11
|
-
def generate(groups: [])
|
12
|
-
gemfile = Gemfile.parse
|
13
|
-
current_lockfile = Lockfile.parse
|
14
|
-
gems = groups.any? ? current_lockfile.gems_exclusively_installed_by(gemfile: gemfile, groups: groups) : nil
|
10
|
+
attr_reader :withheld_gems, :updatable_gems
|
15
11
|
|
16
|
-
|
17
|
-
new(gemfile: gemfile, current_lockfile: current_lockfile, updated_lockfile: updated_lockfile)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
attr_reader :outdated_gems
|
22
|
-
|
23
|
-
def initialize(gemfile:, current_lockfile:, updated_lockfile:)
|
12
|
+
def initialize(current_lockfile:, withheld_gems:, updatable_gems:)
|
24
13
|
@current_lockfile = current_lockfile
|
25
|
-
@
|
26
|
-
|
27
|
-
updated_lockfile_entry = updated_lockfile && updated_lockfile[name]
|
28
|
-
next unless current_lockfile_entry.older_than?(updated_lockfile_entry)
|
29
|
-
|
30
|
-
hash[name] = build_outdated_gem(current_lockfile_entry, updated_lockfile_entry, gemfile[name]&.groups)
|
31
|
-
end.freeze
|
14
|
+
@withheld_gems = withheld_gems.freeze
|
15
|
+
@updatable_gems = updatable_gems.freeze
|
32
16
|
end
|
33
17
|
|
34
|
-
def
|
35
|
-
|
18
|
+
def empty?
|
19
|
+
withheld_gems.empty? && updatable_gems.empty?
|
36
20
|
end
|
37
21
|
|
38
|
-
def
|
39
|
-
@
|
40
|
-
current_lockfile[name].exact_requirement?
|
41
|
-
end.freeze
|
22
|
+
def all_gems
|
23
|
+
@all_gems ||= withheld_gems.merge(updatable_gems)
|
42
24
|
end
|
43
25
|
|
44
26
|
def expand_gems_with_exact_dependencies(*gem_names)
|
@@ -47,13 +29,13 @@ module BundleUpdateInteractive
|
|
47
29
|
end
|
48
30
|
|
49
31
|
def scan_for_vulnerabilities!
|
50
|
-
return false if
|
32
|
+
return false if all_gems.empty?
|
51
33
|
|
52
34
|
Bundler::Audit::Database.update!(quiet: true)
|
53
35
|
audit_report = Bundler::Audit::Scanner.new.report
|
54
36
|
vulnerable_gem_names = Set.new(audit_report.vulnerable_gems.map(&:name))
|
55
37
|
|
56
|
-
|
38
|
+
all_gems.each do |name, gem|
|
57
39
|
gem.vulnerable = (vulnerable_gem_names & [name, *current_lockfile[name].exact_dependencies]).any?
|
58
40
|
end
|
59
41
|
true
|
@@ -67,18 +49,5 @@ module BundleUpdateInteractive
|
|
67
49
|
private
|
68
50
|
|
69
51
|
attr_reader :current_lockfile
|
70
|
-
|
71
|
-
def build_outdated_gem(current_lockfile_entry, updated_lockfile_entry, gemfile_groups)
|
72
|
-
OutdatedGem.new(
|
73
|
-
name: current_lockfile_entry.name,
|
74
|
-
gemfile_groups: gemfile_groups,
|
75
|
-
rubygems_source: updated_lockfile_entry.rubygems_source?,
|
76
|
-
git_source_uri: updated_lockfile_entry.git_source_uri&.to_s,
|
77
|
-
current_version: current_lockfile_entry.version.to_s,
|
78
|
-
current_git_version: current_lockfile_entry.git_version&.strip,
|
79
|
-
updated_version: updated_lockfile_entry.version.to_s,
|
80
|
-
updated_git_version: updated_lockfile_entry.git_version&.strip
|
81
|
-
)
|
82
|
-
end
|
83
52
|
end
|
84
53
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BundleUpdateInteractive
|
4
|
+
class Reporter
|
5
|
+
def initialize(groups: [])
|
6
|
+
@gemfile = Gemfile.parse
|
7
|
+
@current_lockfile = Lockfile.parse
|
8
|
+
@candidate_gems = current_lockfile.gems_exclusively_installed_by(gemfile: gemfile, groups: groups) if groups.any?
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate_report
|
12
|
+
updatable_gems = find_updatable_gems
|
13
|
+
withheld_gems = find_withheld_gems(exclude: updatable_gems.keys)
|
14
|
+
|
15
|
+
Report.new(current_lockfile: current_lockfile, updatable_gems: updatable_gems, withheld_gems: withheld_gems)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :gemfile, :current_lockfile, :candidate_gems
|
21
|
+
|
22
|
+
def find_updatable_gems
|
23
|
+
return {} if candidate_gems && candidate_gems.empty?
|
24
|
+
|
25
|
+
updated_lockfile = Lockfile.parse(BundlerCommands.read_updated_lockfile(*Array(candidate_gems)))
|
26
|
+
current_lockfile.entries.each_with_object({}) do |current_lockfile_entry, hash|
|
27
|
+
name = current_lockfile_entry.name
|
28
|
+
updated_lockfile_entry = updated_lockfile && updated_lockfile[name]
|
29
|
+
next unless current_lockfile_entry.older_than?(updated_lockfile_entry)
|
30
|
+
next if current_lockfile_entry.exact_requirement?
|
31
|
+
|
32
|
+
hash[name] = build_outdated_gem(name, updated_lockfile_entry.version, updated_lockfile_entry.git_version)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_outdated_gem(name, updated_version, updated_git_version)
|
37
|
+
current_lockfile_entry = current_lockfile[name]
|
38
|
+
|
39
|
+
OutdatedGem.new(
|
40
|
+
name: name,
|
41
|
+
gemfile_groups: gemfile[name]&.groups,
|
42
|
+
gemfile_requirement: gemfile[name]&.requirement&.to_s,
|
43
|
+
rubygems_source: current_lockfile_entry.rubygems_source?,
|
44
|
+
git_source_uri: current_lockfile_entry.git_source_uri&.to_s,
|
45
|
+
current_version: current_lockfile_entry.version.to_s,
|
46
|
+
current_git_version: current_lockfile_entry.git_version&.strip,
|
47
|
+
updated_version: updated_version.to_s,
|
48
|
+
updated_git_version: updated_git_version&.strip
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def find_withheld_gems(exclude: [])
|
53
|
+
possibly_withheld = gemfile.dependencies.filter_map do |dep|
|
54
|
+
dep.name if dep.should_include? && !dep.requirement.none? # rubocop:disable Style/InverseMethods
|
55
|
+
end
|
56
|
+
possibly_withheld -= exclude
|
57
|
+
possibly_withheld &= candidate_gems unless candidate_gems.nil?
|
58
|
+
|
59
|
+
return {} if possibly_withheld.empty?
|
60
|
+
|
61
|
+
BundlerCommands.parse_outdated(*possibly_withheld).to_h do |name, newest|
|
62
|
+
[name, build_outdated_gem(name, newest, nil)]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -10,10 +10,12 @@ module BundleUpdateInteractive
|
|
10
10
|
|
11
11
|
@same_segments = new_segments.take_while.with_index { |seg, i| seg == old_segments[i] }
|
12
12
|
@diff_segments = new_segments[same_segments.length..]
|
13
|
+
|
14
|
+
@changed = diff_segments.any? || old_segments.length != new_segments.length
|
13
15
|
end
|
14
16
|
|
15
17
|
def severity
|
16
|
-
return nil
|
18
|
+
return nil unless @changed
|
17
19
|
|
18
20
|
SEVERITIES[same_segments.length] || :patch
|
19
21
|
end
|
@@ -13,6 +13,7 @@ module BundleUpdateInteractive
|
|
13
13
|
autoload :LockfileEntry, "bundle_update_interactive/lockfile_entry"
|
14
14
|
autoload :OutdatedGem, "bundle_update_interactive/outdated_gem"
|
15
15
|
autoload :Report, "bundle_update_interactive/report"
|
16
|
+
autoload :Reporter, "bundle_update_interactive/reporter"
|
16
17
|
autoload :SemverChange, "bundle_update_interactive/semver_change"
|
17
18
|
autoload :VERSION, "bundle_update_interactive/version"
|
18
19
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bundle_update_interactive
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Brictson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.9.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: launchy
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.5.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.5.0
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: pastel
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,7 @@ files:
|
|
108
122
|
- lib/bundle_update_interactive/lockfile_entry.rb
|
109
123
|
- lib/bundle_update_interactive/outdated_gem.rb
|
110
124
|
- lib/bundle_update_interactive/report.rb
|
125
|
+
- lib/bundle_update_interactive/reporter.rb
|
111
126
|
- lib/bundle_update_interactive/semver_change.rb
|
112
127
|
- lib/bundle_update_interactive/version.rb
|
113
128
|
homepage: https://github.com/mattbrictson/bundle_update_interactive
|