strong_versions 0.4.2 → 0.4.3

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: 4b8013eab29eed756e82642806ffa493cdfe95b811a04cbf1a8671f438a7d941
4
- data.tar.gz: 99d19f00b86a8499cac020279583a32da2a14f3639eeb7036df0338113c60f83
3
+ metadata.gz: a19f2c731b09de210cb242a54ed087493741010a84fd98324a42834bfffb32f3
4
+ data.tar.gz: 07fde31789f1c729ede0859404cf5574c20566b3fc2e7e152cc7ee62d45a3d8c
5
5
  SHA512:
6
- metadata.gz: '047964e0861c334509ae41809d5b57ee2cc0f412223148d374d2008ecca64db6ca4eca7df9ebe2d579dcdfc4d988c1d141642b766a47d701ebb866cb281fab01'
7
- data.tar.gz: 48268429b4da20105b90fd3671488180753550f4776467d77e3de0d8c761295b767cd2502a61d99330830a95efde09c129ba9f7e615a2f18e783c885093daf7e
6
+ metadata.gz: 48f230820ee7ebe3e69c6f4e938a01ef12288d6b624869cddf9905701cd2aaeefd3797cd499ea667dd7816182140688bbf3b6a07019e24cea2bd2a98c8b53c28
7
+ data.tar.gz: 129dcaae26d6d8546e52dc7384bbd4ddac4879750399d158517b27198a1fc31a2424566322d343f4959a252dea196a809a26e1acd7fcc63628809d07b157c099
@@ -11,4 +11,8 @@ Style/FormatStringToken:
11
11
  - 'lib/strong_versions/terminal.rb'
12
12
  AllCops:
13
13
  Exclude:
14
- - 'bin/**/*'
14
+ - 'bin/rake'
15
+ - 'bin/console'
16
+ - 'bin/rspec'
17
+ - 'bin/rubocop'
18
+ - 'bin/setup'
data/Makefile CHANGED
@@ -1,6 +1,5 @@
1
1
  .PHONY: test
2
2
  test:
3
- @bin/rspec
4
- @bundle exec bin/strong_versions
5
- @bin/rubocop
6
- @bin/rubocop bin/strong_versions
3
+ @bundle exec rspec
4
+ @bundle exec strong_versions
5
+ @bundle exec rubocop
data/README.md CHANGED
@@ -13,13 +13,13 @@ _StrongVersions_ enforces a strict policy on your `Gemfile` requirements:
13
13
  * The pessimistic `~>` operator must be used for all gem requirement definitions.
14
14
  * If the gem version is greater than 1, the requirement format must be `major.minor`, e.g. `'~> 2.5`'
15
15
  * If the gem version is less than 1, the requirement format must be `major.minor.patch`, e.g. `'~> 0.8.9'`
16
- * An upper bound can be specified as long as a valid pessimistic version is also specified, e.g. `'~> 8.4', '< 8.6.7' # Bug introduced in 8.6.7`
16
+ * A lower/upper bound can be specified as long as a valid pessimistic version is also specified, e.g. `'~> 8.4', '< 8.6.7'`
17
17
  * All gems with a `path` or `git` source are ignored, e.g. `path: '/path/to/gem'`, `git: 'https://github.com/bobf/strong_versions'`
18
18
  * All gems specified in the [ignore list](#ignore) are ignored.
19
19
 
20
- Any gems that do not satisfy these rules will be included in included in the _StrongVersions_ output with details on why they did not meet the standard.
20
+ Any gems that do not satisfy these rules will be included in the _StrongVersions_ output with details on why they did not meet the standard.
21
21
 
22
- The benefit of applying this standard is that, if all gems follow [Semantic Versioning](https://semver.org/) always be relatively safe to run `bundle update` to upgrade to the latest compatible versions of all dependencies. Running `bundle update` often brings advantages both in terms of bug fixes and security updates.
22
+ When all gems in a `Gemfile` follow this convention it SHOULD always be safe to run `bundle update` (assuming all gems adhere to [Semantic Versioning](https://semver.org/)).
23
23
 
24
24
  ![StrongVersions](doc/images/strong-versions-example.png)
25
25
 
@@ -28,7 +28,7 @@ The benefit of applying this standard is that, if all gems follow [Semantic Vers
28
28
  Add the gem to your `Gemfile`
29
29
 
30
30
  ```ruby
31
- gem 'strong_versions', '~> 0.4.2'
31
+ gem 'strong_versions', '~> 0.4.3'
32
32
  ```
33
33
 
34
34
  And rebuild your bundle:
@@ -39,7 +39,7 @@ $ bundle install
39
39
 
40
40
  Or install yourself:
41
41
  ```bash
42
- $ gem install strong_versions -v '0.4.2'
42
+ $ gem install strong_versions -v '0.4.3'
43
43
  ```
44
44
 
45
45
  ## Usage
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'bundler/setup'
4
5
  require 'optparse'
5
6
  require 'shellwords'
6
7
 
@@ -12,11 +13,11 @@ options = {}
12
13
  OptionParser.new do |opts|
13
14
  opts.banner = 'Usage: strong_versions [options]'
14
15
 
15
- opts.on('-a', '--auto-correct', 'Auto-correct (use with caution)') do |_v|
16
+ opts.on('-a', '--auto-correct', 'Auto-correct (use with caution)') do
16
17
  options[:auto_correct] = true
17
18
  end
18
19
 
19
- opts.on('--no-auto-correct', 'Disable auto-correct') do |_v|
20
+ opts.on('--no-auto-correct', 'Disable auto-correct') do
20
21
  options[:auto_correct] = false
21
22
  end
22
23
  end.parse!
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
4
 
3
5
  require 'strong_versions'
4
6
 
5
7
  options = {}
6
8
  OptionParser.new do |opts|
7
- opts.banner = "Usage: strong_versions [options]"
9
+ opts.banner = 'Usage: strong_versions [options]'
8
10
 
9
- opts.on("-a", "--auto-correct", "Auto-correct (use with caution)") do |v|
11
+ opts.on('-a', '--auto-correct', 'Auto-correct (use with caution)') do |_v|
10
12
  options[:auto_correct] = true
11
13
  end
12
14
  end.parse!
@@ -24,12 +26,13 @@ validated = StrongVersions::Dependencies.new(dependencies).validate!(
24
26
  )
25
27
 
26
28
  revalidated = false
27
- revalidated = StrongVersions::Dependencies.new(dependencies).validate!(
28
- except: config.exceptions,
29
- on_failure: 'warn',
30
- auto_correct: false
31
- ) if options[:auto_correct]
29
+ if options[:auto_correct]
30
+ revalidated = StrongVersions::Dependencies.new(dependencies).validate!(
31
+ except: config.exceptions,
32
+ on_failure: 'warn',
33
+ auto_correct: false
34
+ )
35
+ end
32
36
 
33
- exit 0 if validated or revalidated
37
+ exit 0 if validated || revalidated
34
38
  exit 1
35
-
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'pathname'
3
4
  require 'yaml'
4
5
 
5
6
  require 'i18n'
@@ -17,7 +17,7 @@ module StrongVersions
17
17
  return true
18
18
  end
19
19
 
20
- return update_gemfile if auto_correct
20
+ return update_definitions if auto_correct
21
21
 
22
22
  raise_or_warn(options.fetch(:on_failure, 'raise'))
23
23
  summary
@@ -45,38 +45,50 @@ module StrongVersions
45
45
  @terminal.summary(@dependencies.size, @invalid_gems.size)
46
46
  end
47
47
 
48
- def update_gemfile
49
- updated = 0
50
- @dependencies.each do |dependency|
51
- next unless dependency.updatable?
48
+ def updatable_dependencies
49
+ @dependencies.select(&:updatable?)
50
+ end
51
+
52
+ def update_definitions
53
+ @terminal.update_summary(update(:gemfile) + update(:gemspec))
54
+ end
55
+
56
+ def update(subject)
57
+ updatable_dependencies.reduce(0) do |count, dependency|
58
+ next count unless dependency.updatable?
52
59
 
53
- updated += 1 if update_dependency(dependency)
60
+ update_dependency(subject, dependency) ? count : count + 1
54
61
  end
55
- @terminal.update_summary(updated)
56
62
  end
57
63
 
58
- def update_dependency(dependency)
59
- path = dependency.gemfile
64
+ def update_dependency(subject, dependency)
65
+ path = dependency.public_send(subject)
66
+ return if path.nil?
67
+
60
68
  content = File.read(path)
61
- update = replace_gem_definition(dependency, content)
69
+ update = replace_gem_definition(subject, dependency, content)
62
70
  return false if content == update
63
71
 
64
72
  File.write(path, update)
65
- @terminal.gem_update(path, dependency)
73
+ @terminal.gem_update(path, dependency, subject)
66
74
  true
67
75
  end
68
76
 
69
- def replace_gem_definition(dependency, content)
70
- regex = gem_regex(dependency.name)
77
+ def replace_gem_definition(subject, dependency, content)
78
+ regex = gem_regex(subject, dependency.name)
71
79
  match = content.match(regex)
72
80
  return content unless match
73
81
 
74
82
  indent = match.captures.first
75
- content.gsub(regex, "#{indent}#{dependency.suggested_definition}")
83
+ definition = dependency.suggested_definition(subject)
84
+ content.gsub(regex, "#{indent}#{definition}")
76
85
  end
77
86
 
78
- def gem_regex(name)
79
- /^(\s*)gem\s+['"]#{name}['"].*$/
87
+ def gem_regex(subject, name)
88
+ {
89
+ gemfile: /^(\s*)gem\s+['"]#{name}['"].*$/,
90
+ gemspec: /^(\s*)spec.add_[a-z_]*_dependency\s+['"]#{name}['"].*$/
91
+ }.fetch(subject)
80
92
  end
81
93
 
82
94
  def raise_or_warn(on_failure)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StrongVersions
4
+ # rubocop:disable Metrics/ClassLength
4
5
  class Dependency
5
6
  attr_reader :name, :errors
6
7
 
@@ -17,6 +18,10 @@ module StrongVersions
17
18
  Pathname.new(@dependency.gemfile) if @dependency.respond_to?(:gemfile)
18
19
  end
19
20
 
21
+ def gemspec
22
+ Pathname.new(gemspec_path) unless gemspec_path.nil?
23
+ end
24
+
20
25
  def valid?
21
26
  @errors.empty?
22
27
  end
@@ -25,9 +30,10 @@ module StrongVersions
25
30
  GemVersion.new(GemVersion.new(lockfile_version).version_string)
26
31
  end
27
32
 
28
- def suggested_definition
33
+ def suggested_definition(subject = :gemfile)
29
34
  guards = guard_versions.map { |op, version| "'#{op} #{version}'" }
30
- "gem '#{@name}', #{[suggested_version.suggestion, *guards].join(', ')}"
35
+ constraints = [suggested_version.suggestion, *guards].join(', ')
36
+ send(:"suggested_#{subject}_definition", constraints)
31
37
  end
32
38
 
33
39
  def definition
@@ -39,11 +45,38 @@ module StrongVersions
39
45
  end
40
46
 
41
47
  def updatable?
42
- !valid? && gemfile && !suggested_version.missing? && !path_source?
48
+ !valid? && !suggested_version.missing? && !path_source?
43
49
  end
44
50
 
45
51
  private
46
52
 
53
+ def gemspec_path
54
+ _spec, path = gemspec_dependency
55
+ path
56
+ end
57
+
58
+ def gemspec_spec
59
+ spec, _path = gemspec_dependency
60
+ spec
61
+ end
62
+
63
+ def gemspec_dependency
64
+ DependencyFinder.new.gemspec_dependencies.each do |path, specs|
65
+ specs.each do |spec|
66
+ return [spec, path] if spec.name == @dependency.name
67
+ end
68
+ end
69
+ nil
70
+ end
71
+
72
+ def suggested_gemspec_definition(constraints)
73
+ "spec.add_#{gemspec_spec.type}_dependency '#{@name}', #{constraints}"
74
+ end
75
+
76
+ def suggested_gemfile_definition(constraints)
77
+ "gem '#{@name}', #{constraints}"
78
+ end
79
+
47
80
  def versions
48
81
  @dependency.requirements_list.map { |version| parse_version(version) }
49
82
  end
@@ -124,4 +157,5 @@ module StrongVersions
124
157
  I18n.t("strong_versions.#{name}")
125
158
  end
126
159
  end
160
+ # rubocop:enable Metrics/ClassLength
127
161
  end
@@ -6,6 +6,12 @@ module StrongVersions
6
6
  development + runtime
7
7
  end
8
8
 
9
+ def gemspec_dependencies
10
+ Hash[gemspecs.compact.map do |gemspec|
11
+ [gemspec.loaded_from, dependencies]
12
+ end]
13
+ end
14
+
9
15
  private
10
16
 
11
17
  def development
@@ -10,14 +10,14 @@ module StrongVersions
10
10
  puts(color(string, :bright, :red))
11
11
  end
12
12
 
13
- def gem_update(path, gem)
13
+ def gem_update(path, gem, subject)
14
14
  relpath = path.relative_path_from(Pathname.new(Dir.pwd))
15
15
  output = [
16
- color("[#{relpath}] ", :cyan),
17
- color(gem.suggested_definition, :green),
18
- color(' (was: ', :default),
19
- color(gem.definition, :red),
20
- color(')', :default)
16
+ color('[', :cyan),
17
+ color(relpath.to_s, :green),
18
+ color('] ', :cyan),
19
+ color('updated: ', :default),
20
+ color(gem.suggested_definition(subject), :green)
21
21
  ].join
22
22
  puts(output)
23
23
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StrongVersions
4
- VERSION = '0.4.2'
4
+ VERSION = '0.4.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strong_versions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Farrell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-26 00:00:00.000000000 Z
11
+ date: 2020-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n