bundle_update_interactive 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5fa0d1bf9fc3114b352236559c7a91b460b6b2816b3cd0cd3b7bc848fd072b5
4
- data.tar.gz: d70836e166741cf2efe13d188d393e094fe1adf50bb02e64f7e997a853dd65a2
3
+ metadata.gz: 903a652a152b38ae645e7aea5a4216d36f464b8c9de1fb7a912d2a68aeb0a25d
4
+ data.tar.gz: cebf133ae5be56b8706ead28c59ea8d2c11967a0994327fa8ccd8ab41ef99c5c
5
5
  SHA512:
6
- metadata.gz: ab496890f43f89d9519b3e14e32998fad0d888295419dd09ce2d69f546b09a8699e635c31a442aa3990d048dc09d0a864a488307c6f047213369c198aa8b3403
7
- data.tar.gz: 4030b23f6982f0732f4a289d637ff94b1881e5b907377af69dcb0f5125c7fa19f29bb016a957c630a094268f30ecdda1d60f9978f1f9231a7e0cff4ca0b6ab23
6
+ metadata.gz: 170ac818830a83eda22e6b24349e81af25d9aeeace867e839e6e9b96ebd93b19cf3b2e7d72df8b5e3610fe3390ae95791be034dfae7d147f75964a9075c055fe
7
+ data.tar.gz: 8d3c98c30d19335071e3c582e8e828039da65b53231b38968147a4dbf3a13f6532b5bfb9db12e03d6da2a15a88a6f14a3cbf17d8b5531fa62e93515386c3c308
data/README.md CHANGED
@@ -44,6 +44,7 @@ bundle ui
44
44
 
45
45
  - `--commit` [applies each gem update in a discrete git commit](#git-commits)
46
46
  - `--latest` [modifies the Gemfile if necessary to allow the latest gem versions](#allow-latest-versions)
47
+ - `--only-explicit` [updates Gemfile gems only (excluding indirect dependencies)](#exclude-indirect-dependencies)
47
48
  - `-D` / `--exclusively=GROUP` [limits updatable gems by Gemfile groups](#limit-impact-by-gemfile-groups)
48
49
 
49
50
  ## Features
@@ -145,6 +146,16 @@ https://github.com/rails/rails/compare/5a8d894...77dfa65
145
146
 
146
147
  This feature currently works for GitHub, GitLab, and Bitbucket repos.
147
148
 
149
+ ### Exclude indirect dependencies
150
+
151
+ Just like with `bundle outdated`, you can pass `--only-explicit` to limit updates to only gems that are explicitly listed in the Gemfile.
152
+
153
+ ```sh
154
+ bundle update-interactive --only-explicit
155
+ ```
156
+
157
+ This will omit indirect dependencies from the list of gems that can be updated.
158
+
148
159
  ### Limit impact by Gemfile groups
149
160
 
150
161
  The effects of `bundle update-interactive` can be limited to one or more Gemfile groups using the `--exclusively` option:
@@ -5,87 +5,89 @@ require "pastel"
5
5
  require "tty/prompt"
6
6
  require "tty/screen"
7
7
 
8
- class BundleUpdateInteractive::CLI
9
- class MultiSelect
10
- extend BundleUpdateInteractive::StringHelper
8
+ module BundleUpdateInteractive
9
+ class CLI
10
+ class MultiSelect
11
+ extend BundleUpdateInteractive::StringHelper
11
12
 
12
- class List < TTY::Prompt::MultiList
13
- def initialize(prompt, **options)
14
- @opener = options.delete(:opener)
15
- defaults = {
16
- cycle: true,
17
- help_color: :itself.to_proc,
18
- per_page: [TTY::Prompt::Paginator::DEFAULT_PAGE_SIZE, TTY::Screen.height.to_i - 3].max,
19
- quiet: true,
20
- show_help: :always
21
- }
22
- super(prompt, **defaults.merge(options))
23
- end
13
+ class List < TTY::Prompt::MultiList
14
+ def initialize(prompt, **options)
15
+ @opener = options.delete(:opener)
16
+ defaults = {
17
+ cycle: true,
18
+ help_color: :itself.to_proc,
19
+ per_page: [TTY::Prompt::Paginator::DEFAULT_PAGE_SIZE, TTY::Screen.height.to_i - 3].max,
20
+ quiet: true,
21
+ show_help: :always
22
+ }
23
+ super(prompt, **defaults.merge(options))
24
+ end
24
25
 
25
- def selected_names
26
- ""
27
- end
26
+ def selected_names
27
+ ""
28
+ end
28
29
 
29
- # Unregister tty-prompt's default ctrl-a and ctrl-r bindings
30
- alias select_all keyctrl_a
31
- alias reverse_selection keyctrl_r
32
- def keyctrl_a(*); end
33
- def keyctrl_r(*); end
30
+ # Unregister tty-prompt's default ctrl-a and ctrl-r bindings
31
+ alias select_all keyctrl_a
32
+ alias reverse_selection keyctrl_r
33
+ def keyctrl_a(*); end
34
+ def keyctrl_r(*); end
34
35
 
35
- def keypress(event)
36
- case event.value
37
- when "k", "p" then keyup
38
- when "j", "n" then keydown
39
- when "a" then select_all
40
- when "r" then reverse_selection
41
- when "o" then opener&.call(choices[@active - 1].value)
36
+ def keypress(event)
37
+ case event.value
38
+ when "k", "p" then keyup
39
+ when "j", "n" then keydown
40
+ when "a" then select_all
41
+ when "r" then reverse_selection
42
+ when "o" then opener&.call(choices[@active - 1].value)
43
+ end
42
44
  end
43
- end
44
45
 
45
- private
46
+ private
46
47
 
47
- attr_reader :opener
48
- end
48
+ attr_reader :opener
49
+ end
49
50
 
50
- def self.prompt_for_gems_to_update(outdated_gems, prompt: nil)
51
- table = Table.updatable(outdated_gems)
52
- title = "#{pluralize(outdated_gems.length, 'gem')} can be updated."
53
- opener = lambda do |gem|
54
- url = outdated_gems[gem].changelog_uri
55
- Launchy.open(url) unless url.nil?
51
+ def self.prompt_for_gems_to_update(outdated_gems, prompt: nil)
52
+ table = Table.updatable(outdated_gems)
53
+ title = "#{pluralize(outdated_gems.length, 'gem')} can be updated."
54
+ opener = lambda do |gem|
55
+ url = outdated_gems[gem].changelog_uri
56
+ Launchy.open(url) unless url.nil?
57
+ end
58
+ chosen = new(title: title, table: table, prompt: prompt, opener: opener).prompt
59
+ outdated_gems.slice(*chosen)
56
60
  end
57
- chosen = new(title: title, table: table, prompt: prompt, opener: opener).prompt
58
- outdated_gems.slice(*chosen)
59
- end
60
61
 
61
- def initialize(title:, table:, opener: nil, prompt: nil)
62
- @title = title
63
- @table = table
64
- @opener = opener
65
- @tty_prompt = prompt || TTY::Prompt.new(
66
- interrupt: lambda {
67
- puts
68
- exit(130)
69
- }
70
- )
71
- @pastel = BundleUpdateInteractive.pastel
72
- end
62
+ def initialize(title:, table:, opener: nil, prompt: nil)
63
+ @title = title
64
+ @table = table
65
+ @opener = opener
66
+ @tty_prompt = prompt || TTY::Prompt.new(
67
+ interrupt: lambda {
68
+ puts
69
+ exit(130)
70
+ }
71
+ )
72
+ @pastel = BundleUpdateInteractive.pastel
73
+ end
73
74
 
74
- def prompt
75
- choices = table.gem_names.to_h { |name| [table.render_gem(name), name] }
76
- tty_prompt.invoke_select(List, title, choices, help: help, opener: opener)
77
- end
75
+ def prompt
76
+ choices = table.gem_names.to_h { |name| [table.render_gem(name), name] }
77
+ tty_prompt.invoke_select(List, title, choices, help: help, opener: opener)
78
+ end
78
79
 
79
- private
80
+ private
80
81
 
81
- attr_reader :pastel, :table, :opener, :tty_prompt, :title
82
+ attr_reader :pastel, :table, :opener, :tty_prompt, :title
82
83
 
83
- def help
84
- [
85
- pastel.dim("\nPress <space> to select, ↑/↓ move, <a> all, <r> reverse, <o> open url, <enter> to finish."),
86
- "\n ",
87
- table.render_header
88
- ].join
84
+ def help
85
+ [
86
+ pastel.dim("\nPress <space> to select, ↑/↓ move, <a> all, <r> reverse, <o> open url, <enter> to finish."),
87
+ "\n ",
88
+ table.render_header
89
+ ].join
90
+ end
89
91
  end
90
92
  end
91
93
  end
@@ -3,110 +3,120 @@
3
3
  require "optparse"
4
4
 
5
5
  module BundleUpdateInteractive
6
- class CLI::Options
7
- class << self
8
- def parse(argv=ARGV)
9
- options = new
10
- remaining = build_parser(options).parse!(argv.dup)
11
- raise Error, "update-interactive does not accept arguments. See --help for available options." if remaining.any?
12
-
13
- options.freeze
14
- end
6
+ class CLI
7
+ class Options
8
+ class << self
9
+ def parse(argv=ARGV)
10
+ options = new
11
+ remain = build_parser(options).parse!(argv.dup)
12
+ raise Error, "update-interactive does not accept arguments. See --help for available options." if remain.any?
13
+
14
+ options.freeze
15
+ end
15
16
 
16
- def summary
17
- build_parser(new).summarize.join.gsub(/^\s+-.*? /, pastel.yellow('\0'))
18
- end
17
+ def summary
18
+ build_parser(new).summarize.join.gsub(/^\s+-.*? /, pastel.yellow('\0'))
19
+ end
19
20
 
20
- def help # rubocop:disable Metrics/AbcSize
21
- <<~HELP
22
- Provides an easy way to update gems to their latest versions.
21
+ def help # rubocop:disable Metrics/AbcSize
22
+ <<~HELP
23
+ Provides an easy way to update gems to their latest versions.
23
24
 
24
- #{pastel.bold.underline('USAGE')}
25
- #{pastel.green('bundle update-interactive')} #{pastel.yellow('[options]')}
26
- #{pastel.green('bundle ui')} #{pastel.yellow('[options]')}
25
+ #{pastel.bold.underline('USAGE')}
26
+ #{pastel.green('bundle update-interactive')} #{pastel.yellow('[options]')}
27
+ #{pastel.green('bundle ui')} #{pastel.yellow('[options]')}
27
28
 
28
- #{pastel.bold.underline('OPTIONS')}
29
- #{summary}
30
- #{pastel.bold.underline('DESCRIPTION')}
31
- Displays the list of gems that would be updated by `bundle update`, allowing you
32
- to navigate them by keyboard and pick which ones to update. A changelog URL,
33
- when available, is displayed alongside each update. Gems with known security
34
- vulnerabilities are also highlighted.
29
+ #{pastel.bold.underline('OPTIONS')}
30
+ #{summary}
31
+ #{pastel.bold.underline('DESCRIPTION')}
32
+ Displays the list of gems that would be updated by `bundle update`, allowing you
33
+ to navigate them by keyboard and pick which ones to update. A changelog URL,
34
+ when available, is displayed alongside each update. Gems with known security
35
+ vulnerabilities are also highlighted.
35
36
 
36
- Your Gemfile.lock will be updated conservatively based on the gems you select.
37
- Transitive dependencies are not affected.
37
+ Your Gemfile.lock will be updated conservatively based on the gems you select.
38
+ Transitive dependencies are not affected.
38
39
 
39
- More information: #{pastel.blue('https://github.com/mattbrictson/bundle_update_interactive')}
40
+ More information: #{pastel.blue('https://github.com/mattbrictson/bundle_update_interactive')}
40
41
 
41
- #{pastel.bold.underline('EXAMPLES')}
42
- Show all gems that can be updated.
43
- #{pastel.green('bundle update-interactive')}
42
+ #{pastel.bold.underline('EXAMPLES')}
43
+ Show all gems that can be updated.
44
+ #{pastel.green('bundle update-interactive')}
44
45
 
45
- The "ui" command alias can also be used.
46
- #{pastel.green('bundle ui')}
46
+ The "ui" command alias can also be used.
47
+ #{pastel.green('bundle ui')}
47
48
 
48
- Show updates for development and test gems only, leaving production gems untouched.
49
- #{pastel.green('bundle update-interactive')} #{pastel.yellow('-D')}
49
+ Show updates for development and test gems only, leaving production gems untouched.
50
+ #{pastel.green('bundle update-interactive')} #{pastel.yellow('-D')}
50
51
 
51
- Allow the latest gem versions, ignoring Gemfile pins. May modify the Gemfile.
52
- #{pastel.green('bundle update-interactive')} #{pastel.yellow('--latest')}
52
+ Allow the latest gem versions, ignoring Gemfile pins. May modify the Gemfile.
53
+ #{pastel.green('bundle update-interactive')} #{pastel.yellow('--latest')}
53
54
 
54
- HELP
55
- end
55
+ HELP
56
+ end
56
57
 
57
- private
58
+ private
58
59
 
59
- def pastel
60
- BundleUpdateInteractive.pastel
61
- end
60
+ def pastel
61
+ BundleUpdateInteractive.pastel
62
+ end
62
63
 
63
- def build_parser(options) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
64
- OptionParser.new do |parser| # rubocop:disable Metrics/BlockLength
65
- parser.summary_indent = " "
66
- parser.summary_width = 24
67
- parser.on("--commit", "Create a git commit for each selected gem update") do
68
- options.commit = true
69
- end
70
- parser.on("--latest", "Modify the Gemfile to allow the latest gem versions") do
71
- options.latest = true
72
- end
73
- parser.on(
74
- "--exclusively=GROUP",
75
- "Update gems exclusively belonging to the specified Gemfile GROUP(s)"
76
- ) do |value|
77
- options.exclusively = value.split(",").map(&:strip).reject(&:empty?).map(&:to_sym)
78
- end
79
- parser.on("-D", "Shorthand for --exclusively=development,test") do
80
- options.exclusively = %i[development test]
81
- end
82
- parser.on("-v", "--version", "Display version") do
83
- require "bundler"
84
- puts "bundle_update_interactive/#{VERSION} bundler/#{Bundler::VERSION} #{RUBY_DESCRIPTION}"
85
- exit
86
- end
87
- parser.on("-h", "--help", "Show this help") do
88
- puts help
89
- exit
64
+ def build_parser(options) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
65
+ OptionParser.new do |parser| # rubocop:disable Metrics/BlockLength
66
+ parser.summary_indent = " "
67
+ parser.summary_width = 24
68
+ parser.on("--commit", "Create a git commit for each selected gem update") do
69
+ options.commit = true
70
+ end
71
+ parser.on("--latest", "Modify the Gemfile to allow the latest gem versions") do
72
+ options.latest = true
73
+ end
74
+ parser.on("--only-explicit", "Update Gemfile gems only (no indirect dependencies)") do
75
+ options.only_explicit = true
76
+ end
77
+ parser.on(
78
+ "--exclusively=GROUP",
79
+ "Update gems exclusively belonging to the specified Gemfile GROUP(s)"
80
+ ) do |value|
81
+ options.exclusively = value.split(",").map(&:strip).reject(&:empty?).map(&:to_sym)
82
+ end
83
+ parser.on("-D", "Shorthand for --exclusively=development,test") do
84
+ options.exclusively = %i[development test]
85
+ end
86
+ parser.on("-v", "--version", "Display version") do
87
+ require "bundler"
88
+ puts "bundle_update_interactive/#{VERSION} bundler/#{Bundler::VERSION} #{RUBY_DESCRIPTION}"
89
+ exit
90
+ end
91
+ parser.on("-h", "--help", "Show this help") do
92
+ puts help
93
+ exit
94
+ end
90
95
  end
91
96
  end
92
97
  end
93
- end
94
98
 
95
- attr_accessor :exclusively
96
- attr_writer :commit, :latest
99
+ attr_accessor :exclusively
100
+ attr_writer :commit, :latest, :only_explicit
97
101
 
98
- def initialize
99
- @exclusively = []
100
- @commit = false
101
- @latest = false
102
- end
102
+ def initialize
103
+ @exclusively = []
104
+ @commit = false
105
+ @latest = false
106
+ @only_explicit = false
107
+ end
103
108
 
104
- def commit?
105
- @commit
106
- end
109
+ def commit?
110
+ @commit
111
+ end
107
112
 
108
- def latest?
109
- @latest
113
+ def latest?
114
+ @latest
115
+ end
116
+
117
+ def only_explicit?
118
+ @only_explicit
119
+ end
110
120
  end
111
121
  end
112
122
  end
@@ -3,53 +3,55 @@
3
3
  require "delegate"
4
4
  require "pastel"
5
5
 
6
- class BundleUpdateInteractive::CLI
7
- class Row < SimpleDelegator
8
- SEMVER_COLORS = {
9
- major: :red,
10
- minor: :yellow,
11
- patch: :green
12
- }.freeze
13
-
14
- def initialize(outdated_gem)
15
- super
16
- @pastel = BundleUpdateInteractive.pastel
17
- end
6
+ module BundleUpdateInteractive
7
+ class CLI
8
+ class Row < SimpleDelegator
9
+ SEMVER_COLORS = {
10
+ major: :red,
11
+ minor: :yellow,
12
+ patch: :green
13
+ }.freeze
18
14
 
19
- def formatted_gem_name
20
- vulnerable? ? pastel.white.on_red(name) : apply_semver_highlight(name)
21
- end
15
+ def initialize(outdated_gem)
16
+ super
17
+ @pastel = BundleUpdateInteractive.pastel
18
+ end
22
19
 
23
- def formatted_current_version
24
- [current_version.to_s, current_git_version].compact.join(" ")
25
- end
20
+ def formatted_gem_name
21
+ vulnerable? ? pastel.white.on_red(name) : apply_semver_highlight(name)
22
+ end
26
23
 
27
- def formatted_updated_version
28
- version = semver_change.format { |part| apply_semver_highlight(part) }
29
- git_version = apply_semver_highlight(updated_git_version)
24
+ def formatted_current_version
25
+ [current_version.to_s, current_git_version].compact.join(" ")
26
+ end
30
27
 
31
- [version, git_version].compact.join(" ")
32
- end
28
+ def formatted_updated_version
29
+ version = semver_change.format { |part| apply_semver_highlight(part) }
30
+ git_version = apply_semver_highlight(updated_git_version)
33
31
 
34
- def formatted_gemfile_groups
35
- gemfile_groups&.map(&:inspect)&.join(", ")
36
- end
32
+ [version, git_version].compact.join(" ")
33
+ end
37
34
 
38
- def formatted_gemfile_requirement
39
- gemfile_requirement.to_s == ">= 0" ? "" : gemfile_requirement.to_s
40
- end
35
+ def formatted_gemfile_groups
36
+ gemfile_groups&.map(&:inspect)&.join(", ")
37
+ end
41
38
 
42
- def formatted_changelog_uri
43
- pastel.blue(changelog_uri)
44
- end
39
+ def formatted_gemfile_requirement
40
+ gemfile_requirement.to_s == ">= 0" ? "" : gemfile_requirement.to_s
41
+ end
45
42
 
46
- def apply_semver_highlight(value)
47
- color = git_version_changed? ? :cyan : SEMVER_COLORS.fetch(semver_change.severity)
48
- pastel.decorate(value, color)
49
- end
43
+ def formatted_changelog_uri
44
+ pastel.blue(changelog_uri)
45
+ end
50
46
 
51
- private
47
+ def apply_semver_highlight(value)
48
+ color = git_version_changed? ? :cyan : SEMVER_COLORS.fetch(semver_change.severity)
49
+ pastel.decorate(value, color)
50
+ end
52
51
 
53
- attr_reader :pastel
52
+ private
53
+
54
+ attr_reader :pastel
55
+ end
54
56
  end
55
57
  end
@@ -2,83 +2,85 @@
2
2
 
3
3
  require "pastel"
4
4
 
5
- class BundleUpdateInteractive::CLI
6
- class Table
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
5
+ module BundleUpdateInteractive
6
+ class CLI
7
+ class Table
8
+ class << self
9
+ def withheld(gems)
10
+ columns = [
11
+ ["name", :formatted_gem_name],
12
+ ["requirement", :formatted_gemfile_requirement],
13
+ ["current", :formatted_current_version],
14
+ ["latest", :formatted_updated_version],
15
+ ["group", :formatted_gemfile_groups],
16
+ ["url", :formatted_changelog_uri]
17
+ ]
18
+ new(gems, columns)
19
+ end
19
20
 
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)
21
+ def updatable(gems)
22
+ columns = [
23
+ ["name", :formatted_gem_name],
24
+ ["from", :formatted_current_version],
25
+ [nil, "→"],
26
+ ["to", :formatted_updated_version],
27
+ ["group", :formatted_gemfile_groups],
28
+ ["url", :formatted_changelog_uri]
29
+ ]
30
+ new(gems, columns)
31
+ end
30
32
  end
31
- end
32
33
 
33
- def initialize(gems, columns)
34
- @pastel = BundleUpdateInteractive.pastel
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
34
+ def initialize(gems, columns)
35
+ @pastel = BundleUpdateInteractive.pastel
36
+ @headers = columns.map { |header, _| pastel.dim.underline(header) }
37
+ @rows = gems.transform_values do |gem|
38
+ row = Row.new(gem)
39
+ columns.map do |_, col|
40
+ case col
41
+ when Symbol then row.public_send(col).to_s
42
+ when String then col
43
+ end
42
44
  end
43
45
  end
46
+ @column_widths = calculate_column_widths
44
47
  end
45
- @column_widths = calculate_column_widths
46
- end
47
48
 
48
- def gem_names
49
- rows.keys
50
- end
49
+ def gem_names
50
+ rows.keys.sort
51
+ end
51
52
 
52
- def render_header
53
- render_row(headers)
54
- end
53
+ def render_header
54
+ render_row(headers)
55
+ end
55
56
 
56
- def render_gem(name)
57
- row = rows.fetch(name)
58
- render_row(row)
59
- end
57
+ def render_gem(name)
58
+ row = rows.fetch(name)
59
+ render_row(row)
60
+ end
60
61
 
61
- def render
62
- lines = [render_header]
63
- rows.keys.sort.each { |name| lines << render_gem(name) }
64
- lines.join("\n")
65
- end
62
+ def render
63
+ lines = [render_header]
64
+ gem_names.each { |name| lines << render_gem(name) }
65
+ lines.join("\n")
66
+ end
66
67
 
67
- private
68
+ private
68
69
 
69
- attr_reader :column_widths, :pastel, :rows, :headers
70
+ attr_reader :column_widths, :pastel, :rows, :headers
70
71
 
71
- def render_row(row)
72
- row.zip(column_widths).map do |value, width|
73
- padding = width && (" " * (width - pastel.strip(value).length))
74
- "#{value}#{padding}"
75
- end.join(" ")
76
- end
72
+ def render_row(row)
73
+ row.zip(column_widths).map do |value, width|
74
+ padding = width && (" " * (width - pastel.strip(value).length))
75
+ "#{value}#{padding}"
76
+ end.join(" ")
77
+ end
77
78
 
78
- def calculate_column_widths
79
- rows_with_header = [headers, *rows.values]
80
- Array.new(headers.length - 1) do |i|
81
- rows_with_header.map { |values| pastel.strip(values[i]).length }.max
79
+ def calculate_column_widths
80
+ rows_with_header = [headers, *rows.values]
81
+ Array.new(headers.length - 1) do |i|
82
+ rows_with_header.map { |values| pastel.strip(values[i]).length }.max
83
+ end
82
84
  end
83
85
  end
84
86
  end
@@ -61,7 +61,7 @@ module BundleUpdateInteractive
61
61
  def generate_report(options)
62
62
  whisper "Resolving latest gem versions..."
63
63
  updater_class = options.latest? ? Latest::Updater : Updater
64
- updater = updater_class.new(groups: options.exclusively)
64
+ updater = updater_class.new(groups: options.exclusively, only_explicit: options.only_explicit?)
65
65
 
66
66
  report = updater.generate_report
67
67
  unless report.empty?
@@ -22,5 +22,9 @@ module BundleUpdateInteractive
22
22
  def dependencies
23
23
  @dependencies.values
24
24
  end
25
+
26
+ def gem_names
27
+ dependencies.map(&:name)
28
+ end
25
29
  end
26
30
  end
@@ -2,7 +2,8 @@
2
2
 
3
3
  module BundleUpdateInteractive
4
4
  class Updater
5
- def initialize(groups: [])
5
+ def initialize(groups: [], only_explicit: false)
6
+ @only_explicit = only_explicit
6
7
  @gemfile = Gemfile.parse
7
8
  @current_lockfile = Lockfile.parse
8
9
  @candidate_gems = current_lockfile.gems_exclusively_installed_by(gemfile: gemfile, groups: groups) if groups.any?
@@ -32,12 +33,14 @@ module BundleUpdateInteractive
32
33
 
33
34
  private
34
35
 
35
- attr_reader :gemfile, :current_lockfile, :candidate_gems
36
+ attr_reader :gemfile, :current_lockfile, :candidate_gems, :only_explicit
36
37
 
37
38
  def find_updatable_gems
38
39
  return {} if candidate_gems && candidate_gems.empty?
39
40
 
40
- build_outdated_gems(BundlerCommands.read_updated_lockfile(*Array(candidate_gems)))
41
+ updatable = build_outdated_gems(BundlerCommands.read_updated_lockfile(*Array(candidate_gems)))
42
+ updatable = updatable.slice(*gemfile.gem_names) if only_explicit
43
+ updatable
41
44
  end
42
45
 
43
46
  def build_outdated_gems(lockfile_contents)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BundleUpdateInteractive
4
- VERSION = "0.9.0"
4
+ VERSION = "0.10.0"
5
5
  end
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.9.0
4
+ version: 0.10.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-09-19 00:00:00.000000000 Z
11
+ date: 2024-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -168,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
168
  - !ruby/object:Gem::Version
169
169
  version: '0'
170
170
  requirements: []
171
- rubygems_version: 3.5.19
171
+ rubygems_version: 3.5.23
172
172
  signing_key:
173
173
  specification_version: 4
174
174
  summary: Adds an update-interactive command to Bundler