bundle_update_interactive 0.9.0 → 0.10.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
  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