keep_up 0.6.3 → 0.7.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
- SHA1:
3
- metadata.gz: c6e9711c520dce8201a771fec4b0b972817ab8b9
4
- data.tar.gz: 2cbdba7b2d01263a405bc8baee64fb587dc28fd7
2
+ SHA256:
3
+ metadata.gz: 6a35b9a5850635247e718921b7b7a808cf0636c029c6aa17b824336413e6e255
4
+ data.tar.gz: 5e1731815ce612ed28de5926ed93e2419a635aff2dda3a6be8033a8f11df7e2d
5
5
  SHA512:
6
- metadata.gz: 994a91e4ed5c541a0c594cc41868b19be18d5d50dd1c62ca011e947116c64377f24e1ce641b770fb4836db68f5f5bca0aa158f737476a88a79a63dfe166397d4
7
- data.tar.gz: bc4867a1518651a0715ab59c9c418c1ea1a1d822d89235c665232e6c4db1e6c4ca86f741a0472ab4881446631be87dbdc58cd28c1363f409fbade67e8f5cd551
6
+ metadata.gz: ce3b4535216f6b13d9eabe25b1ce32fa37ed90ca06d2c333dba7b24dbe81a61ef7035be57fe56310f196367a3ce460c93acc0c40ad2f1f777dec860359e5f639
7
+ data.tar.gz: 2801b510798abd9df72e6b82d813f55f50644beeaa2b4642a6460992a0deb831e80409bc0901b1773be2d1ec87a377c3342dc28695c2f260c3c79a302f5a3b28
data/.hound.yml ADDED
@@ -0,0 +1,2 @@
1
+ rubocop:
2
+ config_file: .rubocop.yml
data/.rubocop.yml CHANGED
@@ -1,6 +1,12 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ require:
4
+ - rubocop-rspec
5
+
1
6
  AllCops:
2
7
  Exclude:
3
8
  - 'tmp/**/*'
9
+ TargetRubyVersion: 2.3
4
10
 
5
11
  # Dot at end of line makes it clearer that the line is not done
6
12
  Layout/DotPosition:
@@ -29,6 +35,10 @@ Metrics/BlockLength:
29
35
  Metrics/LineLength:
30
36
  Max: 92
31
37
 
38
+ # Allow deeper nesting for spec organization
39
+ RSpec/NestedGroups:
40
+ Max: 4
41
+
32
42
  # Allow and/or for control flow only
33
43
  Style/AndOr:
34
44
  EnforcedStyle: conditionals
@@ -37,10 +47,6 @@ Style/AndOr:
37
47
  Style/GuardClause:
38
48
  MinBodyLength: 2
39
49
 
40
- # Don't use if or unless as modifier if the line gets too long
41
- Style/IfUnlessModifier:
42
- MaxLineLength: 60
43
-
44
50
  # Explicite numbers are often clearer, and more robust.
45
51
  Style/NumericPredicate:
46
52
  Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,17 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2018-12-03 09:08:01 +0100 using RuboCop version 0.60.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: CountComments, ExcludedMethods.
11
+ Metrics/MethodLength:
12
+ Max: 17
13
+
14
+ # Offense count: 1
15
+ Security/Eval:
16
+ Exclude:
17
+ - 'lib/keep_up/bundle.rb'
data/.simplecov ADDED
@@ -0,0 +1,9 @@
1
+ SimpleCov.start do
2
+ track_files 'lib/**/*.rb'
3
+ add_filter 'spec/'
4
+ coverage_dir 'tmp/coverage'
5
+ end
6
+
7
+ SimpleCov.at_exit do
8
+ SimpleCov.result.format!
9
+ end
data/.travis.yml CHANGED
@@ -1,17 +1,20 @@
1
1
  sudo: false
2
2
  language: ruby
3
- rvm:
4
- - 2.2.6
5
- - 2.3.3
6
- - 2.4.0
7
3
 
8
4
  before_install:
9
- - rvm use @global
10
- - gem uninstall bundler -x
11
- - gem install bundler --version=1.13.7
12
- - bundler --version
13
5
  - git config --global user.email "you@example.com"
14
6
  - git config --global user.name "Your Name"
7
+ - gem update --system
8
+
9
+ rvm:
10
+ - 2.3
11
+ - 2.4
12
+ - 2.5
13
+ - ruby-head
14
+
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
15
18
 
16
19
  branches:
17
20
  only:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0 / 2018-12-10
4
+
5
+ * Interface with Bundler via its CLI
6
+ * Perform a real `bundle update` for each update dependency. This means gems
7
+ will actually be installed in each step.
8
+ * Drop support for Bundler versions below 1.15.
9
+ * Delegate finding available update candidates to Bundler.
10
+ * Gracefully handle git dependencies when collecting update candidates
11
+ * Do not attempt to update requirements with more than one element
12
+ * Restore effect of the `--local` flag.
13
+
3
14
  ## 0.6.3 / 2017-10-27
4
15
 
5
16
  * Filter out pre-releases when searching for dependencies to support
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in keep_up.gemspec
data/README.md CHANGED
@@ -17,7 +17,7 @@ Before running KeepUp, it's probably nice to start a new branch. Also, KeepUp
17
17
  will refuse to run if your checkout directory is not clean, or if your
18
18
  Gemfile.lock is not up-to-date.
19
19
 
20
- Run keep_up in your project directory:
20
+ Run `keep_up` in your project directory:
21
21
 
22
22
  $ keep_up
23
23
 
@@ -64,8 +64,9 @@ git commits and tags, and push the `.gem` file to
64
64
 
65
65
  ## Contributing
66
66
 
67
- Bug reports and pull requests are welcome on GitHub at
68
- https://github.com/mvz/keep_up. This project is intended to be a safe,
67
+ Bug reports and pull requests are welcome at
68
+ [`keep_up`'s repository](https://github.com/mvz/keep_up) on GitHub.
69
+ This project is intended to be a safe,
69
70
  welcoming space for collaboration, and contributors are expected to adhere to
70
71
  the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
71
72
 
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
  require 'cucumber/rake/task'
data/bin/keep_up CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'optparse'
4
5
  require_relative '../lib/keep_up'
@@ -8,19 +9,28 @@ options = {
8
9
  test_command: 'bundle exec rake',
9
10
  skip: []
10
11
  }
11
- OptionParser.new do |parser|
12
- parser.on('--[no-]local') do |local|
12
+
13
+ opt_parser = OptionParser.new do |parser|
14
+ parser.on('--[no-]local', 'Only consider locally installed gems') do |local|
13
15
  options[:local] = local
14
16
  end
15
-
16
- parser.on('--test-command=COMMAND') do |command|
17
+ parser.on('--test-command=COMMAND', 'Run COMMAND to test each update') do |command|
17
18
  options[:test_command] = command
18
19
  end
19
-
20
- parser.on('--skip=SKIPPED_GEM') do |gemname|
20
+ parser.on('--skip=SKIPPED_GEM', 'Do not consider SKIPPED_GEM for updating') do |gemname|
21
21
  options[:skip] << gemname
22
22
  end
23
- end.parse!
23
+ parser.on_tail('-h', '--help', 'Show this message') do
24
+ puts parser
25
+ exit
26
+ end
27
+ parser.on_tail('-v', '--version', 'Show version') do
28
+ puts "#{parser.program_name} #{KeepUp::VERSION}\n"
29
+ exit
30
+ end
31
+ end
32
+
33
+ opt_parser.parse!
24
34
 
25
35
  begin
26
36
  KeepUp::Application.new(options).run
data/keep_up.gemspec CHANGED
@@ -1,4 +1,6 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'keep_up/version'
4
6
 
@@ -22,10 +24,12 @@ Gem::Specification.new do |spec|
22
24
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
25
  spec.require_paths = ['lib']
24
26
 
25
- spec.add_runtime_dependency 'bundler', '~> 1.13'
27
+ spec.required_ruby_version = '>= 2.3.0'
28
+
29
+ spec.add_runtime_dependency 'bundler', '~> 1.15'
26
30
 
27
31
  spec.add_development_dependency 'aruba', '~> 0.14.2'
28
- spec.add_development_dependency 'pry'
29
32
  spec.add_development_dependency 'rake', '~> 12.0'
30
33
  spec.add_development_dependency 'rspec', '~> 3.0'
34
+ spec.add_development_dependency 'simplecov', '~> 0.16.1'
31
35
  end
@@ -1,10 +1,8 @@
1
- require 'bundler'
2
- require 'open3'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'runner'
3
4
  require_relative 'bundle'
4
- require_relative 'bundler_definition_builder'
5
- require_relative 'gem_index'
6
5
  require_relative 'null_filter'
7
- require_relative 'repository'
8
6
  require_relative 'skip_filter'
9
7
  require_relative 'updater'
10
8
  require_relative 'version_control'
@@ -16,52 +14,55 @@ module KeepUp
16
14
 
17
15
  # Main application
18
16
  class Application
19
- def initialize(local:, test_command:, skip:)
17
+ def initialize(local:, test_command:, skip:, runner: Runner)
20
18
  @test_command = test_command
21
19
  @local = local
22
20
  @skip = skip
21
+ @runner = runner
23
22
  end
24
23
 
25
24
  def run
26
- sanity_check
25
+ check_version_control_clean
26
+ check_bundle_lockfile
27
27
  update_all_dependencies
28
28
  report_done
29
29
  end
30
30
 
31
31
  private
32
32
 
33
- attr_reader :skip, :local
33
+ attr_reader :skip, :local, :runner
34
+
35
+ def check_version_control_clean
36
+ return if version_control.clean?
37
+
38
+ raise BailOut, "Commit or stash your work before running 'keep_up'"
39
+ end
40
+
41
+ def check_bundle_lockfile
42
+ return if bundle.check? && version_control.clean?
34
43
 
35
- def sanity_check
36
- version_control.clean? or
37
- raise BailOut, "Commit or stash your work before running 'keep_up'"
38
- bundle.check? or
39
- raise BailOut, "Make sure your Gemfile.lock is up-to-date before running 'keep_up'"
44
+ version_control.revert_changes
45
+ raise BailOut, "Make sure your Gemfile.lock is up-to-date before running 'keep_up'"
40
46
  end
41
47
 
42
48
  def update_all_dependencies
43
49
  Updater.new(bundle: bundle,
44
- repository: Repository.new(index: index),
45
50
  version_control: version_control,
46
51
  filter: filter).run
47
52
  end
48
53
 
49
54
  def version_control
50
- @version_control ||= VersionControl.new
55
+ @version_control ||= VersionControl.new(runner: runner)
51
56
  end
52
57
 
53
58
  def bundle
54
- @bundle ||= Bundle.new(definition_builder: definition_builder)
59
+ @bundle ||= Bundle.new(runner: runner, local: local)
55
60
  end
56
61
 
57
62
  def report_done
58
63
  puts 'All done!'
59
64
  end
60
65
 
61
- def definition_builder
62
- @definition_builder ||= BundlerDefinitionBuilder.new(local: local)
63
- end
64
-
65
66
  def filter
66
67
  @filter ||= if skip.any?
67
68
  SkipFilter.new(skip)
@@ -69,9 +70,5 @@ module KeepUp
69
70
  NullFilter.new
70
71
  end
71
72
  end
72
-
73
- def index
74
- GemIndex.new(definition_builder: definition_builder)
75
- end
76
73
  end
77
74
  end
@@ -1,132 +1,121 @@
1
- require 'bundler'
1
+ # frozen_string_literal: true
2
+
2
3
  require_relative 'gemfile_filter'
3
4
  require_relative 'gemspec_filter'
4
5
  require_relative 'dependency'
5
- require_relative 'one'
6
6
 
7
7
  module KeepUp
8
8
  # A Gemfile with its current set of locked dependencies.
9
9
  class Bundle
10
- def initialize(definition_builder:)
11
- @definition_builder = definition_builder
12
- end
10
+ OUTDATED_MATCHER =
11
+ /([^ ]*) \(newest ([^,]*), installed ([^,]*)(?:, requested (.*))?\)/.freeze
12
+ UPDATE_MATCHER =
13
+ /(?:Using|Installing|Fetching) ([^ ]*) ([^ ]*)(?: \(was (.*))?\)/.freeze
13
14
 
14
- def dependencies
15
- gemspec_dependencies + gemfile_dependencies + transitive_dependencies
15
+ def initialize(runner:, local:)
16
+ @runner = runner
17
+ @local = local
16
18
  end
17
19
 
18
- def apply_updated_dependency(dependency)
19
- report_intent dependency
20
- update_gemfile_contents(dependency)
21
- update_gemspec_contents(dependency)
22
- result = update_lockfile(dependency)
23
- report_result dependency, result
24
- result
20
+ def dependencies
21
+ @dependencies ||=
22
+ begin
23
+ command = "bundle outdated --parseable#{' --local' if @local}"
24
+ lines = run_filtered command, OUTDATED_MATCHER
25
+ lines.map do |name, newest, version, requirement|
26
+ requirement_list = requirement&.split(/,\s*/)
27
+ requirement_list ||= fetch_gemspec_dependency_requirements(name)
28
+ version = version.split(' ').first
29
+ newest = newest.split(' ').first
30
+ Dependency.new(name: name,
31
+ locked_version: version,
32
+ newest_version: newest,
33
+ requirement_list: requirement_list)
34
+ end
35
+ end
25
36
  end
26
37
 
27
38
  def check?
28
- bundler_definition.to_lock == File.read('Gemfile.lock')
39
+ _, status = @runner.run2 'bundle check'
40
+ status == 0
29
41
  end
30
42
 
31
- private
32
-
33
- attr_reader :definition_builder
43
+ def update_gemfile_contents(update)
44
+ update = find_specification_update(dependencies, update)
45
+ return unless update
34
46
 
35
- def report_intent(dependency)
36
- print "Updating #{dependency.name}"
47
+ update_specification_contents(update, 'Gemfile', GemfileFilter)
37
48
  end
38
49
 
39
- def report_result(dependency, result)
40
- if result
41
- puts " to #{result.version}"
42
- else
43
- puts " to #{dependency.version}"
44
- puts 'Update failed'
45
- end
46
- end
50
+ def update_gemspec_contents(update)
51
+ return unless gemspec_name
47
52
 
48
- def gemfile_dependencies
49
- raw = if Bundler::VERSION >= '1.15.'
50
- bundler_lockfile.dependencies.values
51
- else
52
- bundler_lockfile.dependencies
53
- end
54
- build_dependencies raw
55
- end
53
+ update = find_specification_update(dependencies, update)
54
+ return unless update
56
55
 
57
- def gemspec_dependencies
58
- gemspec_source = bundler_lockfile.sources.
59
- find { |it| it.is_a? Bundler::Source::Gemspec }
60
- return [] unless gemspec_source
61
- build_dependencies gemspec_source.gemspec.dependencies
56
+ update_specification_contents(update, gemspec_name, GemspecFilter)
62
57
  end
63
58
 
64
- def transitive_dependencies
65
- build_dependencies bundler_lockfile.specs.flat_map(&:dependencies).uniq
59
+ # Update lockfile and return resulting spec, or false in case of failure
60
+ def update_lockfile(update)
61
+ update_name = update.name
62
+ command = "bundle update#{' --local' if @local} --conservative #{update_name}"
63
+ lines = run_filtered command, UPDATE_MATCHER
64
+ lines.each do |name, version, old_version|
65
+ next unless name == update_name && old_version
66
+
67
+ current = Gem::Specification.new(name, old_version)
68
+ result = Gem::Specification.new(name, version)
69
+ return result if result.version > current.version
70
+ end
71
+ nil
66
72
  end
67
73
 
68
- def build_dependencies(deps)
69
- deps.map { |dep| build_dependency dep }.compact
70
- end
74
+ private
71
75
 
72
- def build_dependency(dep)
73
- spec = locked_spec dep
74
- return unless spec
75
- Dependency.new(name: dep.name,
76
- requirement_list: dep.requirement.as_list,
77
- locked_version: spec.version)
76
+ def gemspec
77
+ @gemspec ||= eval File.read(gemspec_name) if gemspec_name
78
78
  end
79
79
 
80
- def locked_spec(dep)
81
- bundler_lockfile.specs.find { |it| it.name == dep.name }
80
+ def gemspec_dependencies
81
+ @gemspec_dependencies ||= if gemspec
82
+ gemspec.dependencies
83
+ else
84
+ []
85
+ end
82
86
  end
83
87
 
84
- def bundler_lockfile
85
- @bundler_lockfile ||= bundler_definition.locked_gems
86
- end
88
+ def fetch_gemspec_dependency_requirements(name)
89
+ dep = gemspec_dependencies.find { |it| it.name == name }
90
+ return unless dep
87
91
 
88
- def bundler_definition
89
- @bundler_definition ||= definition_builder.build(false)
92
+ dep.requirements_list
90
93
  end
91
94
 
92
- def update_gemfile_contents(update)
93
- current_dependency = gemfile_dependencies.find { |it| it.name == update.name }
94
- return unless current_dependency
95
- return if current_dependency.matches_spec?(update)
96
-
97
- update = current_dependency.generalize_specification(update)
95
+ def find_specification_update(current_dependencies, update)
96
+ current_dependency = current_dependencies.find { |it| it.name == update.name }
97
+ return if !current_dependency || current_dependency.matches_spec?(update)
98
98
 
99
- contents = File.read 'Gemfile'
100
- updated_contents = GemfileFilter.apply(contents, update)
101
- File.write 'Gemfile', updated_contents
99
+ current_dependency.generalize_specification(update)
102
100
  end
103
101
 
104
- def update_gemspec_contents(update)
105
- current_dependency = gemspec_dependencies.find { |it| it.name == update.name }
106
- return unless current_dependency
107
- return if current_dependency.matches_spec?(update)
108
-
109
- update = current_dependency.generalize_specification(update)
110
-
111
- contents = File.read gemspec_name
112
- updated_contents = GemspecFilter.apply(contents, update)
113
- File.write gemspec_name, updated_contents
102
+ def update_specification_contents(update, file, filter)
103
+ File.write file, filter.apply(File.read(file), update)
114
104
  end
115
105
 
116
106
  def gemspec_name
117
- @gemspec_name ||= One.fetch(Dir.glob('*.gemspec'))
107
+ @gemspec_name ||= Dir.glob('*.gemspec').first
118
108
  end
119
109
 
120
- # Update lockfile and return resulting spec, or false in case of failure
121
- def update_lockfile(update)
122
- Bundler.clear_gemspec_cache
123
- definition = definition_builder.build(gems: [update.name])
124
- definition.lock('Gemfile.lock')
125
- current = locked_spec(update)
126
- result = definition.specs.find { |it| it.name == update.name }
127
- result if result.version > current.version
128
- rescue Bundler::VersionConflict
129
- false
110
+ def run_filtered(command, regexp)
111
+ result = @runner.run command
112
+ lines = result.split("\n").reject(&:empty?)
113
+ lines.map do |line|
114
+ matchdata = regexp.match line
115
+ next unless matchdata
116
+
117
+ matchdata.to_a[1..-1]
118
+ end.compact
130
119
  end
131
120
  end
132
121
  end
@@ -1,13 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KeepUp
2
4
  # Single dependency with its current locked version.
3
5
  class Dependency
4
- def initialize(name:, requirement_list:, locked_version:)
6
+ def initialize(name:, requirement_list:, locked_version:, newest_version:)
5
7
  @name = name
6
8
  @requirement_list = requirement_list
7
9
  @locked_version = Gem::Version.new locked_version
10
+ @newest_version = Gem::Version.new newest_version
8
11
  end
9
12
 
10
- attr_reader :name, :locked_version
13
+ attr_reader :name, :locked_version, :newest_version
11
14
 
12
15
  def requirement
13
16
  @requirement ||= Gem::Requirement.new @requirement_list
@@ -19,8 +22,10 @@ module KeepUp
19
22
 
20
23
  def generalize_specification(specification)
21
24
  return specification if requirement.exact?
25
+
22
26
  segments = specification.version.segments
23
27
  return specification if segments.count <= segment_count
28
+
24
29
  version = segments.take(segment_count).join('.')
25
30
  Gem::Specification.new(specification.name, version)
26
31
  end
@@ -28,6 +33,7 @@ module KeepUp
28
33
  def ==(other)
29
34
  other.name == name &&
30
35
  other.locked_version == locked_version &&
36
+ other.newest_version == newest_version &&
31
37
  other.requirement == requirement
32
38
  end
33
39
 
@@ -1,15 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KeepUp
2
4
  # Filter to update dependency information in a Gemfile.
3
5
  module GemfileFilter
4
6
  def self.apply(contents, dependency)
7
+ matcher = dependency_matcher(dependency)
5
8
  contents.each_line.map do |line|
6
- if line =~ /^(\s*gem\s+['"]#{dependency.name}['"],\s+['"](~> *)?)[^'"]*(['"].*)/m
9
+ if line =~ matcher
7
10
  match = Regexp.last_match
8
- "#{match[1]}#{dependency.version}#{match[3]}"
11
+ "#{match[1]}#{dependency.version}#{match[2]}"
9
12
  else
10
13
  line
11
14
  end
12
15
  end.join
13
16
  end
17
+
18
+ def self.dependency_matcher(dependency)
19
+ /
20
+ ^(\s*gem\s+['"]#{dependency.name}['"],
21
+ \s+\[?['"](?:~>|=)?\ *)
22
+ [^'"]*
23
+ (['"]\]?[^\]]*)
24
+ $
25
+ /mx
26
+ end
14
27
  end
15
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KeepUp
2
4
  # Filter to update dependency information in a Gemspec.
3
5
  module GemspecFilter
@@ -18,7 +20,9 @@ module KeepUp
18
20
  ^(.*_dependency
19
21
  \s*(?:\(\s*)?
20
22
  (?:['"]|%q.)#{dependency.name}.(?:\.freeze)?,
21
- \s+\[?['"](?:~>|=)?\ *)[^'"]*(['"].*)
23
+ \s+\[?['"](?:~>|=)?\ *)
24
+ [^'"]*
25
+ (['"]\]?[^'"]*)$
22
26
  /mx
23
27
  end
24
28
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KeepUp
2
4
  # Simple filter that acccepts everything.
3
5
  class NullFilter
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module KeepUp
6
+ # Encapsulate knowledge of running external commands
7
+ module Runner
8
+ module_function
9
+
10
+ def run(command)
11
+ stdout, = run2 command
12
+ stdout
13
+ end
14
+
15
+ def run2(command)
16
+ Open3.capture2 command
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KeepUp
2
4
  # Filter that skips dependencies if their name is on the list of things to be skipped.
3
5
  class SkipFilter
@@ -1,20 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'null_filter'
2
4
 
3
5
  module KeepUp
4
6
  # Apply potential updates to a Gemfile.
5
7
  class Updater
6
- attr_reader :bundle, :repository, :version_control, :filter
8
+ attr_reader :bundle, :version_control, :filter
7
9
 
8
- def initialize(bundle:, repository:, version_control:, filter: NullFilter.new)
10
+ def initialize(bundle:, version_control:,
11
+ filter: NullFilter.new, out: STDOUT)
9
12
  @bundle = bundle
10
- @repository = repository
11
13
  @version_control = version_control
12
14
  @filter = filter
15
+ @out = out
13
16
  end
14
17
 
15
18
  def run
16
19
  possible_updates.each do |update|
17
- result = bundle.apply_updated_dependency update
20
+ result = apply_updated_dependency update
18
21
  if result
19
22
  version_control.commit_changes result
20
23
  else
@@ -26,7 +29,39 @@ module KeepUp
26
29
  def possible_updates
27
30
  bundle.dependencies.
28
31
  select { |dep| filter.call dep }.
29
- map { |dep| repository.updated_dependency_for dep }.compact.uniq
32
+ map { |dep| updated_dependency_for dep }.compact.uniq
33
+ end
34
+
35
+ private
36
+
37
+ def apply_updated_dependency(dependency)
38
+ report_intent dependency
39
+ bundle.update_gemfile_contents(dependency)
40
+ bundle.update_gemspec_contents(dependency)
41
+ result = bundle.update_lockfile(dependency)
42
+ report_result dependency, result
43
+ result
44
+ end
45
+
46
+ def report_intent(dependency)
47
+ @out.print "Updating #{dependency.name}"
48
+ end
49
+
50
+ def report_result(dependency, result)
51
+ if result
52
+ @out.puts " to #{result.version}"
53
+ else
54
+ @out.puts " to #{dependency.version}"
55
+ @out.puts 'Update failed'
56
+ end
57
+ end
58
+
59
+ def updated_dependency_for(dependency)
60
+ locked_version = dependency.locked_version
61
+ newest_version = dependency.newest_version
62
+ return unless newest_version > locked_version
63
+
64
+ Gem::Specification.new(dependency.name, newest_version)
30
65
  end
31
66
  end
32
67
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KeepUp
2
- VERSION = '0.6.3'.freeze
4
+ VERSION = '0.7.0'
3
5
  end
@@ -1,16 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KeepUp
2
4
  # Interface to the version control system (only Git is supported).
3
5
  class VersionControl
6
+ def initialize(runner:)
7
+ @runner = runner
8
+ end
9
+
4
10
  def commit_changes(dependency)
5
- `git commit -am "Auto-update #{dependency.name} to #{dependency.version}"`
11
+ @runner.run "git commit -am 'Auto-update #{dependency.name} to #{dependency.version}'"
6
12
  end
7
13
 
8
14
  def revert_changes
9
- `git reset --hard`
15
+ @runner.run 'git reset --hard'
10
16
  end
11
17
 
12
18
  def clean?
13
- `git status -s` == ''
19
+ @runner.run('git status -s') == ''
14
20
  end
15
21
  end
16
22
  end
data/lib/keep_up.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'keep_up/version'
2
4
  require_relative 'keep_up/application'
3
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keep_up
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matijs van Zuijlen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-27 00:00:00.000000000 Z
11
+ date: 2018-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.13'
19
+ version: '1.15'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.13'
26
+ version: '1.15'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: aruba
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -39,47 +39,47 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.14.2
41
41
  - !ruby/object:Gem::Dependency
42
- name: pry
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '12.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '12.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '12.0'
61
+ version: '3.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '12.0'
68
+ version: '3.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rspec
70
+ name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '3.0'
75
+ version: 0.16.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '3.0'
82
+ version: 0.16.1
83
83
  description: Automatically update the dependencies listed in your Gemfile, Gemfile.lock,
84
84
  and gemspec.
85
85
  email:
@@ -91,8 +91,11 @@ extra_rdoc_files: []
91
91
  files:
92
92
  - ".dockerignore"
93
93
  - ".gitignore"
94
+ - ".hound.yml"
94
95
  - ".rspec"
95
96
  - ".rubocop.yml"
97
+ - ".rubocop_todo.yml"
98
+ - ".simplecov"
96
99
  - ".travis.yml"
97
100
  - CHANGELOG.md
98
101
  - CODE_OF_CONDUCT.md
@@ -106,14 +109,11 @@ files:
106
109
  - lib/keep_up.rb
107
110
  - lib/keep_up/application.rb
108
111
  - lib/keep_up/bundle.rb
109
- - lib/keep_up/bundler_definition_builder.rb
110
112
  - lib/keep_up/dependency.rb
111
- - lib/keep_up/gem_index.rb
112
113
  - lib/keep_up/gemfile_filter.rb
113
114
  - lib/keep_up/gemspec_filter.rb
114
115
  - lib/keep_up/null_filter.rb
115
- - lib/keep_up/one.rb
116
- - lib/keep_up/repository.rb
116
+ - lib/keep_up/runner.rb
117
117
  - lib/keep_up/skip_filter.rb
118
118
  - lib/keep_up/updater.rb
119
119
  - lib/keep_up/version.rb
@@ -130,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
130
  requirements:
131
131
  - - ">="
132
132
  - !ruby/object:Gem::Version
133
- version: '0'
133
+ version: 2.3.0
134
134
  required_rubygems_version: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - ">="
@@ -138,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
138
  version: '0'
139
139
  requirements: []
140
140
  rubyforge_project:
141
- rubygems_version: 2.6.13
141
+ rubygems_version: 2.7.6
142
142
  signing_key:
143
143
  specification_version: 4
144
144
  summary: Automatically update your dependencies
@@ -1,26 +0,0 @@
1
- require 'bundler'
2
-
3
- module KeepUp
4
- # Creates Bunder::Definition objects.
5
- class BundlerDefinitionBuilder
6
- def initialize(local: false)
7
- @local = local
8
- end
9
-
10
- def build(lock)
11
- definition = Bundler::Definition.build('Gemfile', 'Gemfile.lock', lock)
12
- if lock
13
- if local
14
- definition.resolve_with_cache!
15
- else
16
- definition.resolve_remotely!
17
- end
18
- end
19
- definition
20
- end
21
-
22
- private
23
-
24
- attr_reader :local
25
- end
26
- end
@@ -1,24 +0,0 @@
1
- module KeepUp
2
- # Searches possibly remote gem index to find potential dependency updates.
3
- class GemIndex
4
- def initialize(definition_builder:)
5
- @definition_builder = definition_builder
6
- end
7
-
8
- def search(dependency)
9
- index.search(Bundler::Dependency.new(dependency.name, nil))
10
- end
11
-
12
- private
13
-
14
- attr_reader :definition_builder
15
-
16
- def definition
17
- @definition ||= definition_builder.build(true)
18
- end
19
-
20
- def index
21
- @index ||= definition.index
22
- end
23
- end
24
- end
data/lib/keep_up/one.rb DELETED
@@ -1,13 +0,0 @@
1
- module KeepUp
2
- # Fetch value from an array with exactly one element
3
- module One
4
- def self.fetch(arr)
5
- case arr.count
6
- when 1
7
- arr.first
8
- else
9
- raise 'Expected exactly one element'
10
- end
11
- end
12
- end
13
- end
@@ -1,16 +0,0 @@
1
- module KeepUp
2
- # Picks updated versions for dependencies.
3
- class Repository
4
- attr_reader :index
5
-
6
- def initialize(index:)
7
- @index = index
8
- end
9
-
10
- def updated_dependency_for(dependency)
11
- candidates = index.search(dependency).reject { |it| it.version.prerelease? }
12
- latest = candidates.sort_by(&:version).last
13
- latest unless latest.version <= dependency.locked_version
14
- end
15
- end
16
- end