keep_up 0.6.3 → 0.7.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
- 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