gouteur 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 174d0cdcc37fbca2d808a91be97a17feb70140ef403de6f95f91b0ce74e8beda
4
- data.tar.gz: 6f886d8d85c43065b821371a916e44414580a5e5ead255d811916942d9387b70
3
+ metadata.gz: 56cca423043e101ebc4014b3b5bb4bc8edf1dd27ce25493b6ec918fe6da669c8
4
+ data.tar.gz: a92f38d08ce56549acae5b6696e2519f0cbef9820750bb29cef419f867448ccc
5
5
  SHA512:
6
- metadata.gz: 7806e1a42dacd49fa222c7eb9c73f21373786540c7a8d2c06ae8bba06dfb71a5d98e8e81ff6bfcda063da86b91d377c7a2b01ab2a5ee4e6bf0fdeac638a472b6
7
- data.tar.gz: 84c3649159b02083c7ac31d94e14657a04807cc05f99f41cea3ea35939106394e88337118ce2c72a384fa6ec0c41f83d3c92bf3ccd9ff980c6fcdde9b4e9b571
6
+ metadata.gz: 56dfc4cb69657e92322d1e7105bb8d2df73de9b230673758eb98842ec39b5033e56d7d7c6ba39a41a8149734c0db6898157844b7f3b31427febd9b5711cbef2b
7
+ data.tar.gz: 9b5ceb4857337045681e84448301cafb8985f441816c8f9188706f70b5e95f736b62d739bc90d0abe9f46a4888ff6b59702d3c511e79b193d65ec8beaa337318
@@ -8,7 +8,7 @@ jobs:
8
8
 
9
9
  strategy:
10
10
  matrix:
11
- ruby: [ '2.5', '3.0', 'ruby-head' ]
11
+ ruby: [ '2.6', '3.0', 'ruby-head' ]
12
12
 
13
13
  steps:
14
14
  - uses: actions/checkout@v2
data/.rubocop.yml CHANGED
@@ -6,11 +6,20 @@ AllCops:
6
6
  SuggestExtensions: false
7
7
  TargetRubyVersion: 2.5
8
8
 
9
+ Gemspec/RequireMFA:
10
+ Enabled: false
11
+
9
12
  Layout/LineLength:
10
13
  Max: 80
11
14
 
12
15
  Lint/AmbiguousBlockAssociation:
13
16
  Enabled: false
14
17
 
18
+ Lint/AmbiguousOperatorPrecedence:
19
+ Enabled: false
20
+
21
+ Style/FetchEnvVar:
22
+ Enabled: false
23
+
15
24
  Style/FrozenStringLiteralComment:
16
25
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.1.0] - 2023-02-21
4
+
5
+ ### Added
6
+
7
+ - Added force flag to force testing, irrespective of version constraints
8
+ - Support passing dotfile repo names to CLI
9
+ - Support setting custom names for repos in dotfile
10
+ - Support git SSH/SCP addresses
11
+
12
+ ## [1.0.2] - 2022-09-24
13
+
14
+ ### Fixed
15
+
16
+ - Fixed error message when a repo's `before` task fails
17
+ - Fixed dependency version mismatch detection for recent bundler versions
18
+
3
19
  ## [1.0.1] - 2021-03-09
4
20
 
5
21
  ### Fixed
data/Gemfile CHANGED
@@ -13,4 +13,4 @@ gem 'relaxed-rubocop'
13
13
 
14
14
  gem 'example_repo', '0.1.0', path: './spec/gouteur/example_repo'
15
15
 
16
- gem 'byebug'
16
+ gem 'debug'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gouteur (1.0.0)
4
+ gouteur (1.1.0)
5
5
 
6
6
  PATH
7
7
  remote: spec/gouteur/example_repo
@@ -12,48 +12,57 @@ GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
14
  ast (2.4.2)
15
- byebug (11.1.3)
16
- diff-lcs (1.4.4)
17
- parallel (1.20.1)
18
- parser (3.0.0.0)
15
+ debug (1.7.1)
16
+ irb (>= 1.5.0)
17
+ reline (>= 0.3.1)
18
+ diff-lcs (1.5.0)
19
+ io-console (0.6.0)
20
+ irb (1.6.2)
21
+ reline (>= 0.3.0)
22
+ json (2.6.3)
23
+ parallel (1.22.1)
24
+ parser (3.2.1.0)
19
25
  ast (~> 2.4.1)
20
- rainbow (3.0.0)
21
- rake (13.0.3)
22
- regexp_parser (2.0.3)
26
+ rainbow (3.1.1)
27
+ rake (13.0.6)
28
+ regexp_parser (2.7.0)
23
29
  relaxed-rubocop (2.5)
24
- rexml (3.2.4)
25
- rspec (3.10.0)
26
- rspec-core (~> 3.10.0)
27
- rspec-expectations (~> 3.10.0)
28
- rspec-mocks (~> 3.10.0)
29
- rspec-core (3.10.1)
30
- rspec-support (~> 3.10.0)
31
- rspec-expectations (3.10.1)
30
+ reline (0.3.2)
31
+ io-console (~> 0.5)
32
+ rexml (3.2.5)
33
+ rspec (3.12.0)
34
+ rspec-core (~> 3.12.0)
35
+ rspec-expectations (~> 3.12.0)
36
+ rspec-mocks (~> 3.12.0)
37
+ rspec-core (3.12.1)
38
+ rspec-support (~> 3.12.0)
39
+ rspec-expectations (3.12.2)
32
40
  diff-lcs (>= 1.2.0, < 2.0)
33
- rspec-support (~> 3.10.0)
34
- rspec-mocks (3.10.2)
41
+ rspec-support (~> 3.12.0)
42
+ rspec-mocks (3.12.3)
35
43
  diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.10.0)
37
- rspec-support (3.10.2)
38
- rubocop (1.9.1)
44
+ rspec-support (~> 3.12.0)
45
+ rspec-support (3.12.0)
46
+ rubocop (1.45.1)
47
+ json (~> 2.3)
39
48
  parallel (~> 1.10)
40
- parser (>= 3.0.0.0)
49
+ parser (>= 3.2.0.0)
41
50
  rainbow (>= 2.2.2, < 4.0)
42
51
  regexp_parser (>= 1.8, < 3.0)
43
- rexml
44
- rubocop-ast (>= 1.2.0, < 2.0)
52
+ rexml (>= 3.2.5, < 4.0)
53
+ rubocop-ast (>= 1.24.1, < 2.0)
45
54
  ruby-progressbar (~> 1.7)
46
- unicode-display_width (>= 1.4.0, < 3.0)
47
- rubocop-ast (1.4.1)
48
- parser (>= 2.7.1.5)
55
+ unicode-display_width (>= 2.4.0, < 3.0)
56
+ rubocop-ast (1.26.0)
57
+ parser (>= 3.2.1.0)
49
58
  ruby-progressbar (1.11.0)
50
- unicode-display_width (2.0.0)
59
+ unicode-display_width (2.4.2)
51
60
 
52
61
  PLATFORMS
53
62
  ruby
54
63
 
55
64
  DEPENDENCIES
56
- byebug
65
+ debug
57
66
  example_repo (= 0.1.0)!
58
67
  gouteur!
59
68
  rake (~> 13.0)
data/README.md CHANGED
@@ -37,7 +37,9 @@ repos:
37
37
  ref: some_specific_branch # optional, default is the default branch
38
38
  before: setup_special_dependency # optional, bundle is always installed
39
39
  tasks: ['rspec', 'rake foo'] # optional, default is `rake`
40
+ name: cool_gem # optional, defaults to repo name from uri, e.g. `some_gem`
40
41
  locked: true # optional, prevents setting an incompatible VERSION
42
+ force: true # optional, forces test even if VERSION is incompatible
41
43
  ```
42
44
 
43
45
  Then simply `bundle exec gouteur` or add the rake task to your Rakefile:
@@ -64,7 +66,11 @@ tasks: 'rspec --pattern "**/{,*}{keyword1,keyword2}{,*,*/**/*}_spec.rb"'`
64
66
  From the shell:
65
67
 
66
68
  ```shell
69
+ # example: check one dependent repo
67
70
  gouteur 'https://github.com/foo/bar'
71
+
72
+ # see other usage options:
73
+ gouteur --help
68
74
  ```
69
75
 
70
76
  From Ruby:
@@ -86,7 +92,6 @@ Possible future improvements:
86
92
  - support more sources of code, e.g. latest release, private GitHub repositories
87
93
  - improve performance by tracing & rerunning only specs/tests that use the gem
88
94
  - save time in MiniTest by forcing it to run in fail-fast mode like RSpec
89
- - add help output and more options to the CLI executable
90
95
  - other ideas? open an issue!
91
96
 
92
97
  ## License
@@ -3,15 +3,16 @@ require 'yaml'
3
3
  module Gouteur
4
4
  # main process class
5
5
  class Checker
6
- attr_reader :repo
6
+ attr_reader :repo, :force
7
7
 
8
- def self.call(repo, silent: false)
9
- new(repo, silent: silent).call
8
+ def self.call(repo, silent: false, force: repo&.force?)
9
+ new(repo, silent: silent, force: force).call
10
10
  end
11
11
 
12
- def initialize(repo, silent: false)
12
+ def initialize(repo, silent: false, force: repo&.force?)
13
13
  @repo = repo
14
14
  @silent = silent
15
+ @force = force
15
16
  end
16
17
 
17
18
  def call
@@ -21,7 +22,8 @@ module Gouteur
21
22
 
22
23
  run_tasks(adapted: false)
23
24
 
24
- create_adapted_gemfile
25
+ repo.gemfile.create_adapted(drop_version_constraint: force)
26
+ repo.remove_host_from_gemspecs if force
25
27
  install_adapted_bundle or return handle_incompatible_semver
26
28
 
27
29
  run_tasks(adapted: true)
@@ -58,36 +60,6 @@ module Gouteur
58
60
  )
59
61
  end
60
62
 
61
- def create_adapted_gemfile
62
- content = File.exist?(gemfile_path) ? File.read(gemfile_path) : ''
63
- adapted_content = adapt_gemfile_content(content)
64
- File.open(adapted_gemfile_path, 'w') { |f| f.puts(adapted_content) }
65
- end
66
-
67
- def adapt_gemfile_content(content)
68
- new_entry = "gem '#{Host.name}', path: '#{Host.root}' # set by gouteur "
69
-
70
- existing_ref_pattern =
71
- /^ *gem +(?<q>'|")#{Host.name}\k<q>(?<v> *,\s*(?<q2>'|")[^'"]+\k<q2>*)?/
72
-
73
- if content =~ existing_ref_pattern
74
- content.gsub(existing_ref_pattern) do
75
- # keep version specification if there was one
76
- new_entry.sub(/(?=, path:)/, Regexp.last_match[:v].to_s)
77
- end
78
- else
79
- "#{content}\n#{new_entry}\n"
80
- end
81
- end
82
-
83
- def gemfile_path
84
- repo.bundle.gemfile_path
85
- end
86
-
87
- def adapted_gemfile_path
88
- "#{repo.bundle.gemfile_path}.gouteur"
89
- end
90
-
91
63
  def install_adapted_bundle
92
64
  result = repo.bundle.install(env: adaptation_env)
93
65
  if result.success?
@@ -105,7 +77,7 @@ module Gouteur
105
77
  def indicates_incompatible_semver?(result)
106
78
  result.exitstatus == BUNDLER_INCOMPATIBLE_VERSION_CODE ||
107
79
  result.exitstatus == BUNDLER_GEM_NOT_FOUND_CODE &&
108
- result.stderr =~ /following version/
80
+ result.stderr =~ /following gems matching|following version/
109
81
  end
110
82
 
111
83
  def handle_incompatible_semver
@@ -116,7 +88,7 @@ module Gouteur
116
88
 
117
89
  def adaptation_env
118
90
  {
119
- 'BUNDLE_GEMFILE' => adapted_gemfile_path,
91
+ 'BUNDLE_GEMFILE' => repo.gemfile.adapted_path,
120
92
  'SPEC_OPTS' => '--fail-fast', # saves time with rspec tasks
121
93
  }
122
94
  end
data/lib/gouteur/cli.rb CHANGED
@@ -1,9 +1,13 @@
1
+ require 'optparse'
2
+
1
3
  module Gouteur
2
4
  # command line interface - prints to stdout and returns true or false
3
5
  module CLI
4
6
  module_function
5
7
 
6
- def call(args = ARGV)
8
+ def call(argv = ARGV)
9
+ args = option_parser.parse!(argv)
10
+
7
11
  repos = pick_repos(args)
8
12
  if repos.empty?
9
13
  puts '', Message.no_repos, ''
@@ -11,16 +15,54 @@ module Gouteur
11
15
  end
12
16
 
13
17
  repos.all? do |repo|
14
- success, message = Gouteur::Checker.call(repo)
18
+ success, message = Gouteur::Checker.call(repo, force: !!@force)
15
19
  puts '', message, ''
16
20
  success
17
21
  end
18
22
  end
19
23
 
24
+ def option_parser
25
+ @force = false
26
+
27
+ OptionParser.new do |opts|
28
+ opts.banner = <<~SH
29
+ Usage: gouteur [repos] [options]
30
+
31
+ Examples:
32
+ gouteur https://github.com/me/my_repo
33
+ gouteur my_repo # my_repo must be listed in .gouteur.yml
34
+
35
+ SH
36
+
37
+ opts.separator 'Options:'
38
+
39
+ opts.on("-f", "--force", "Force tests, override version constraints") do
40
+ @force = true
41
+ end
42
+
43
+ opts.on("-v", "--version", "Show gouteur version") do
44
+ puts "gouteur #{Gouteur::VERSION}"
45
+ exit
46
+ end
47
+
48
+ opts.on("-h", "--help", "Show this help") do
49
+ puts opts
50
+ exit
51
+ end
52
+ end
53
+ end
54
+
20
55
  def pick_repos(args)
21
- repos = args.map { |arg| Gouteur::Repo.new(uri: arg) }
22
- repos = Dotfile.repos if repos.empty?
23
- repos
56
+ dotfile_repos = Dotfile.repos
57
+ return dotfile_repos if args.empty?
58
+
59
+ args.map do |arg|
60
+ if dotfile_repo = dotfile_repos.find { |r| r.name == arg }
61
+ dotfile_repo
62
+ else
63
+ Gouteur::Repo.new(uri: arg)
64
+ end
65
+ end
24
66
  end
25
67
  end
26
68
  end
@@ -0,0 +1,66 @@
1
+ module Gouteur
2
+ # Gemfile of a repository that depends on the library under test
3
+ class Gemfile
4
+ attr_reader :original_path
5
+
6
+ def initialize(original_path)
7
+ @original_path = original_path
8
+ end
9
+
10
+ def adapted_path
11
+ "#{original_path}.gouteur"
12
+ end
13
+
14
+ def content
15
+ File.exist?(original_path) ? File.read(original_path) : ''
16
+ end
17
+
18
+ def create_adapted(drop_version_constraint: false)
19
+ adapted_content = self.class.adapt(
20
+ content,
21
+ drop_version_constraint: drop_version_constraint,
22
+ )
23
+ File.open(adapted_path, 'w') { |f| f.puts(adapted_content) }
24
+ end
25
+
26
+ def self.adapt(content, drop_version_constraint: false)
27
+ new_entry = "gem '#{Host.name}', path: '#{Host.root}' # set by gouteur "
28
+
29
+ existing_ref_pattern =
30
+ /
31
+ ^\s*gem\W+#{Host.name}\W
32
+ (?<version>
33
+ \s*,\s*
34
+ (?:
35
+ #{VERSION_NUMBER_PATTERN}
36
+ |
37
+ \[(?:\s*#{VERSION_NUMBER_PATTERN}\s*,?\s*)+\]
38
+ )
39
+ )?
40
+ /x
41
+
42
+ return "#{content}\n#{new_entry}\n" unless content =~ existing_ref_pattern
43
+
44
+ content.gsub(existing_ref_pattern) do
45
+ if drop_version_constraint
46
+ new_entry
47
+ else
48
+ # keep version specification if there was one
49
+ new_entry.sub(/(?=, path:)/, Regexp.last_match[:version].to_s)
50
+ end
51
+ end
52
+ end
53
+
54
+ VERSION_NUMBER_PATTERN =
55
+ /
56
+ \d+\.\d+ # float
57
+ |
58
+ \d+ # int
59
+ |
60
+ (?:%[qQ]?)?
61
+ (?:
62
+ '[^']+'|"[^"]+"|\[[^\]]+\]|\{[^}]+\}|\([^)]+\)|<[^>]+>
63
+ ) # string literal
64
+ /x.freeze
65
+ end
66
+ end
@@ -75,6 +75,8 @@ module Gouteur
75
75
  The new version number of `#{Host.name}` is incompatible with the version requirements specified by `#{repo}`.
76
76
 
77
77
  Releasing incompatible versions is considered OK by default, so tasks will be SKIPPED in this case. If you want gouteur to FAIL in this case, set the `locked` flag.
78
+
79
+ Use the `force` flag to override this version constraint and run the tests anyway.
78
80
  MSG
79
81
  end
80
82
 
@@ -84,7 +86,7 @@ module Gouteur
84
86
 
85
87
  The new version number of `#{Host.name}` is incompatible with the version requirements specified by `#{repo}`.
86
88
 
87
- Incompatible version numbers can be allowed by removing the `locked` flag. This will make gouteur SKIP the tasks in this case.
89
+ Incompatible version numbers can be allowed by removing the `locked` flag. This will make gouteur SKIP the tasks in this case unless the `force` flag is set.
88
90
  MSG
89
91
  end
90
92
 
data/lib/gouteur/repo.rb CHANGED
@@ -6,13 +6,22 @@ module Gouteur
6
6
  attr_reader :uri, :name, :ref, :tasks
7
7
  alias to_s name
8
8
 
9
- def initialize(uri:, ref: nil, before: [], tasks: 'rake', locked: false)
10
- @uri = URI.parse(uri)
11
- @name = extract_name_from_uri(uri)
9
+ def initialize(
10
+ uri:,
11
+ name: nil,
12
+ ref: nil,
13
+ before: [],
14
+ tasks: 'rake',
15
+ locked: false,
16
+ force: false
17
+ )
18
+ @uri = uri
19
+ @name = name || extract_name_from_uri(uri)
12
20
  @ref = ref
13
21
  @before = Array(before)
14
22
  @tasks = Array(tasks)
15
23
  @locked = !!locked
24
+ @force = !!force
16
25
  end
17
26
 
18
27
  def fetch
@@ -35,10 +44,26 @@ module Gouteur
35
44
  @bundle ||= Gouteur::Bundle.new(clone_path)
36
45
  end
37
46
 
47
+ def gemfile
48
+ @gemfile ||= Gouteur::Gemfile.new(bundle.gemfile_path)
49
+ end
50
+
38
51
  def locked?
39
52
  @locked
40
53
  end
41
54
 
55
+ def force?
56
+ @force
57
+ end
58
+
59
+ def remove_host_from_gemspecs
60
+ Dir[File.join(clone_path, '*.gemspec')].each do |gemspec_path|
61
+ content = File.read(gemspec_path)
62
+ new_content = content.gsub(/^.+_dependency.+\b#{Host.name}\b.+$/, '')
63
+ File.write(gemspec_path, new_content)
64
+ end
65
+ end
66
+
42
67
  private
43
68
 
44
69
  def extract_name_from_uri(uri)
data/lib/gouteur/shell.rb CHANGED
@@ -29,7 +29,7 @@ module Gouteur
29
29
  attr_reader :stdout, :stderr, :exitstatus
30
30
 
31
31
  def initialize(args:, pwd:, stdout:, stderr:, status:)
32
- @args = args
32
+ @args = Array(args)
33
33
  @pwd = pwd
34
34
  @stdout = stdout
35
35
  @stderr = stderr
@@ -1,3 +1,3 @@
1
1
  module Gouteur
2
- VERSION = '1.0.1'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
data/lib/gouteur.rb CHANGED
@@ -4,6 +4,7 @@ require 'gouteur/bundle'
4
4
  require 'gouteur/checker'
5
5
  require 'gouteur/cli'
6
6
  require 'gouteur/dotfile'
7
+ require 'gouteur/gemfile'
7
8
  require 'gouteur/host'
8
9
  require 'gouteur/message'
9
10
  require 'gouteur/repo'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gouteur
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janosch Müller
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-09 00:00:00.000000000 Z
11
+ date: 2023-02-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Run tests of dependent gems against your changes.
14
14
  email:
@@ -39,6 +39,7 @@ files:
39
39
  - lib/gouteur/checker.rb
40
40
  - lib/gouteur/cli.rb
41
41
  - lib/gouteur/dotfile.rb
42
+ - lib/gouteur/gemfile.rb
42
43
  - lib/gouteur/host.rb
43
44
  - lib/gouteur/message.rb
44
45
  - lib/gouteur/rake_task.rb
@@ -67,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
68
  - !ruby/object:Gem::Version
68
69
  version: '0'
69
70
  requirements: []
70
- rubygems_version: 3.2.3
71
+ rubygems_version: 3.4.1
71
72
  signing_key:
72
73
  specification_version: 4
73
74
  summary: See if your lib is still digestible.