matrixeval-ruby 0.1.0 → 0.2.2

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: 4af8c6ab00f9e0a26f787dc9e3161f92c824f8aa2f06bd6809ff6b7875535d22
4
- data.tar.gz: 6dc2c0275ba1b28a733f8bc72f627ac53cce9aae606087b9becb5b0a2c23fe7b
3
+ metadata.gz: 3c1fa003fd849f1a5baf6c9393c5210e030e52a14c044308f6732b602c196027
4
+ data.tar.gz: 652ab5ecd63138e426a002aae768c7bd61214785ef8a8eaa698cffa2eddda1ae
5
5
  SHA512:
6
- metadata.gz: c37a896625ce715a31fdc3506139aaa1025412c3f354cd5d8874ec6c3412c460757c08868e120ac412908c15bd3b686236b7bd4dfb891793590fa85df9b99078
7
- data.tar.gz: 4610fa81ab3b5a00ab202ecf1a082ababc89f48a9af23d826e41dd1252528e61e837761c4d422c59a2e1ebc5942b4e785303d20e22567b5f46e078d43aedc8e8
6
+ metadata.gz: fc85db98392512e7683fbfa96c54e4f34ff2f5c248ab07ceac57bd18a6781cdfac45325b874c1580c068b5a1f56a8653bc0d943baea6fcd391e3baf521038dd4
7
+ data.tar.gz: af503dd911a0522975061dfb37696470adedafc4a6868019480e89cfd51c686bb5aa4f5d848683dfe9b52ba94be0d34cb7fbb7478a262c6fe62f8964f0c5c6a1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2022-02-06
3
+ ## [0.2.2] - 2022-02-11
4
+
5
+ - Auto remove containers
6
+
7
+ ## [0.2.1] - 2022-02-11
8
+
9
+ - Fix a assignment method issue
10
+
11
+ ## [0.2.0] - 2022-02-10
12
+
13
+ - Change config format from 0.1 to 0.2
14
+ - CLI description
15
+ - Other errors fix
16
+
17
+ ## [0.1.1] - 2022-02-09
18
+
19
+ - Fix a execution report issue
20
+
21
+ ## [0.1.0] - 2022-02-09
4
22
 
5
23
  - Initial release
data/README.md CHANGED
@@ -1,9 +1,6 @@
1
- # Matrixeval::Ruby
2
-
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/matrixeval/ruby`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
1
+ # matrixeval-ruby
6
2
 
3
+ Test your ruby code against multiple versions of dependencies like Ruby, Rails, Env ...
7
4
  ## Installation
8
5
 
9
6
  Add this line to your application's Gemfile:
@@ -22,7 +19,22 @@ Or install it yourself as:
22
19
 
23
20
  ## Usage
24
21
 
25
- TODO: Write usage instructions here
22
+ Initialize
23
+
24
+ ```bash
25
+ matrixeval init
26
+ ```
27
+
28
+ Customize `matrixeval.yml` file and run commands like:
29
+
30
+ ```bash
31
+ matrixeval --all bundle install
32
+ matrixeval --all rspec
33
+ matrixeval --ruby 3.0 rspec a_spec.rb
34
+ matrixeval --ruby 3.1 --rails 7.0 rake test
35
+ matrixeval bash
36
+ ```
37
+ Run `matrixeval --help` for more details
26
38
 
27
39
  ## Development
28
40
 
@@ -32,7 +44,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
44
 
33
45
  ## Contributing
34
46
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/matrixeval-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/matrixeval-ruby/blob/main/CODE_OF_CONDUCT.md).
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/matrixeval/matrixeval-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/matrixeval-ruby/blob/main/CODE_OF_CONDUCT.md).
36
48
 
37
49
  ## License
38
50
 
@@ -40,4 +52,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
52
 
41
53
  ## Code of Conduct
42
54
 
43
- Everyone interacting in the Matrixeval::Ruby project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/matrixeval-ruby/blob/main/CODE_OF_CONDUCT.md).
55
+ Everyone interacting in the Matrixeval::Ruby project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/matrixeval/matrixeval-ruby/blob/main/CODE_OF_CONDUCT.md).
data/exe/matrixeval CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'matrixeval/ruby'
4
- puts "Hello, MatrixEval!"
4
+
5
5
  Matrixeval.start(ARGV)
data/exe/meval CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'matrixeval/ruby'
4
- puts "Hello, MatrixEval!"
4
+
5
5
  Matrixeval.start(ARGV)
@@ -24,11 +24,58 @@ module Matrixeval
24
24
 
25
25
  def parse!
26
26
  OptionParser.new do |opts|
27
- opts.banner = "Usage: meval/matrixeval --[VECTOR_KEY] [VECTOR_CHOICE] [COMMAND] [COMMAND_OPTIONS]"
27
+ opts.version = Matrixeval::Ruby::VERSION
28
+ opts.program_name = ""
29
+ opts.banner = <<~USAGE
30
+ Usage:
31
+ matrixeval(meval) [OPTIONS] COMMAND
32
+ USAGE
33
+
34
+ opts.separator ""
35
+ opts.separator "Options:"
36
+
37
+ opts.on "-a", "--all", "# Run the COMMAND against all matrix combinations"
28
38
 
29
39
  Config.vectors.each do |vector|
30
- opts.on("--#{vector.key} [VERSION]", "Set #{vector.key} version")
40
+ # short = "-#{vector.short_key}"
41
+ long = "--#{vector.key} [VERSION]"
42
+ desc = [
43
+ "# Run the COMMAND against a specific #{vector.key} version",
44
+ "# Options: #{vector.variants.map(&:key).join("/")}",
45
+ "# Default: #{vector.default_variant.key}",
46
+ "# Customizable"
47
+ ]
48
+ opts.separator ""
49
+ opts.on(long, *desc)
50
+ end
51
+
52
+ opts.separator ""
53
+ opts.separator "Commands: #{Config.commands.join("/")} (Customizable)"
54
+
55
+ opts.separator ""
56
+ opts.separator "MatrixEval Options:"
57
+
58
+ opts.on("-h", "--help", "# Show help") do
59
+ puts opts.help
60
+ exit
31
61
  end
62
+
63
+ opts.on("-v", "--version", "# Show version") do
64
+ puts opts.version
65
+ exit
66
+ end
67
+
68
+ opts.separator ""
69
+ opts.separator "Customizations:"
70
+ opts.separator " You can customize all options in matrixeval.yml"
71
+
72
+ opts.separator ""
73
+ opts.separator "Example:"
74
+ opts.separator " matrixeval --all bundle install"
75
+ opts.separator " matrixeval --ruby 3.0 rspec a_spec.rb"
76
+ opts.separator " matrixeval --ruby 3.1 --active_model 7.0 rake test"
77
+ opts.separator " matrixeval bash"
78
+
32
79
  end.parse!(context_arguments, into: options)
33
80
  end
34
81
 
@@ -2,6 +2,8 @@ require_relative "./command_line/parse_context_arguments"
2
2
 
3
3
  module Matrixeval
4
4
  module Ruby
5
+ COMMANDS = ['rake', 'rspec', 'bundle', 'bash']
6
+
5
7
  class CommandLine
6
8
 
7
9
  attr_reader :argv
@@ -10,38 +12,42 @@ module Matrixeval
10
12
  @argv = argv
11
13
  end
12
14
 
15
+ def valid?
16
+ init? ||
17
+ !context_options.empty? ||
18
+ !seperator_index.nil?
19
+ end
20
+
13
21
  def init?
14
- argv[0] == 'init'
22
+ @argv[0] == 'init'
15
23
  end
16
24
 
17
25
  def all?
18
- argv[0] == 'all'
26
+ context_options[:all]
19
27
  end
20
28
 
21
29
  def context_options
22
- ParseContextArguments.call(context_arguments)
30
+ @context_options ||= ParseContextArguments.call(context_arguments)
23
31
  end
24
32
 
25
33
  def context_arguments
26
- argv[0...seperator_index]
34
+ arguments = @argv[0...seperator_index]
35
+ arguments << "-h" if @argv.empty?
36
+ arguments
27
37
  end
28
38
 
29
39
  def rest_arguments
30
- argv[seperator_index..-1]
40
+ @argv[seperator_index..-1]
31
41
  end
32
42
 
33
43
  private
34
44
 
35
45
  def seperator_index
36
- argv.index do |argument|
37
- seperator_commands.include?(argument)
46
+ @argv.index do |argument|
47
+ Config.commands.include?(argument)
38
48
  end
39
49
  end
40
50
 
41
- def seperator_commands
42
- ['rake', 'rspec', 'bundle', 'bash']
43
- end
44
-
45
51
  end
46
52
  end
47
53
  end
@@ -2,6 +2,9 @@ module Matrixeval
2
2
  module Ruby
3
3
  class Config
4
4
  class YAML
5
+
6
+ class MissingError < StandardError; end
7
+
5
8
  class << self
6
9
 
7
10
  def create
@@ -25,6 +28,8 @@ module Matrixeval
25
28
  end
26
29
 
27
30
  def yaml
31
+ raise MissingError unless File.exist?(path)
32
+
28
33
  ::YAML.load File.read(path)
29
34
  end
30
35
 
@@ -49,6 +49,11 @@ module Matrixeval
49
49
  YAML["parallel_workers"] || "number_of_processors"
50
50
  end
51
51
 
52
+ def commands
53
+ cmds = YAML["commands"] || []
54
+ COMMANDS + cmds
55
+ end
56
+
52
57
  end
53
58
  end
54
59
  end
@@ -0,0 +1,15 @@
1
+ module Matrixeval
2
+ module Ruby
3
+ class Container
4
+
5
+ attr_reader :image, :env
6
+
7
+ def initialize(options)
8
+ options ||= {}
9
+ @image = options["image"]
10
+ @env = options["env"] || {}
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -29,7 +29,7 @@ module Matrixeval
29
29
 
30
30
  Config.main_vector_variants.map do |variant|
31
31
  services[variant.docker_compose_service_name] = {
32
- "image" => variant.image,
32
+ "image" => variant.container.image,
33
33
  "volumes" => mounts(variant),
34
34
  "environment" => {
35
35
  "BUNDLE_PATH" => "/bundle",
@@ -37,7 +37,7 @@ module Matrixeval
37
37
  "BUNDLE_APP_CONFIG" => "/bundle",
38
38
  "BUNDLE_BIN" => "/bundle/bin",
39
39
  "PATH" => "/app/bin:/bundle/bin:$PATH"
40
- },
40
+ }.merge(variant.container.env),
41
41
  "working_dir" => "/app"
42
42
  }
43
43
  end
@@ -5,6 +5,12 @@ module Matrixeval
5
5
  module Ruby
6
6
  class DockerCompose
7
7
 
8
+ class << self
9
+ def clean_containers
10
+ system("docker compose -f .matrixeval/docker-compose.yml rm --all -f >> /dev/null 2>&1")
11
+ end
12
+ end
13
+
8
14
  attr_reader :context
9
15
 
10
16
  def initialize(context)
@@ -20,9 +20,13 @@ module Matrixeval
20
20
  def initialize(argv)
21
21
  @argv = argv
22
22
  @command = CommandLine.new(argv)
23
+ @threads ||= []
24
+ @matrixeval_results ||= []
23
25
  end
24
26
 
25
27
  def start
28
+ validates
29
+
26
30
  if command.init?
27
31
  init
28
32
  elsif command.all?
@@ -30,12 +34,32 @@ module Matrixeval
30
34
  else
31
35
  run_a_specific_context
32
36
  end
37
+ rescue OptionParser::InvalidOption => e
38
+ puts <<~ERROR
39
+ #{e.message}
40
+ See 'matrixeval --help'
41
+ ERROR
42
+ exit
43
+ rescue Config::YAML::MissingError
44
+ puts "Please run 'matrixeval init' first to generate matrixeval.yml"
45
+ exit
33
46
  ensure
34
47
  turn_on_stty_opost
48
+ DockerCompose.clean_containers
35
49
  end
36
50
 
37
51
  private
38
52
 
53
+ def validates
54
+ return if command.valid?
55
+
56
+ puts <<~ERROR
57
+ matrixeval: '#{argv.join(' ')}' is not a MatrixEval command.
58
+ See 'matrixeval --help'
59
+ ERROR
60
+ exit
61
+ end
62
+
39
63
  def init
40
64
  Config::YAML.create
41
65
  Gitignore.update
@@ -47,6 +71,8 @@ module Matrixeval
47
71
  GemfileLocks.create
48
72
  Gitignore.update
49
73
 
74
+ pull_all_images
75
+
50
76
  if workers_count == 1
51
77
  run_all_contexts_sequentially
52
78
  else
@@ -62,17 +88,17 @@ module Matrixeval
62
88
  docker_compose = DockerCompose.new(context)
63
89
  success = docker_compose.run(command.rest_arguments)
64
90
 
65
- matrixeval_results << [context, !!success]
91
+ @matrixeval_results << [context, !!success]
66
92
  end
67
93
 
68
94
  report
69
95
  end
70
96
 
71
97
  def run_all_contexts_in_parallel
72
- parallel do |contexts|
98
+ parallel(contexts) do |sub_contexts|
73
99
  Thread.current[:matrixeval_results] = []
74
100
 
75
- contexts.each do |context|
101
+ sub_contexts.each do |context|
76
102
  docker_compose = DockerCompose.new(context)
77
103
  success = docker_compose.run(command.rest_arguments)
78
104
 
@@ -98,15 +124,28 @@ module Matrixeval
98
124
  docker_compose.run(command.rest_arguments)
99
125
  end
100
126
 
127
+ def pull_all_images
128
+ parallel(Config.main_vector_variants) do |sub_variants|
129
+ sub_variants.each do |variant|
130
+ puts "Docker image check/pull #{variant.container.image}"
131
+ image_exists = system %Q{[ -n "$(docker images -q #{variant.container.image})" ]}
132
+ next if image_exists
133
+
134
+ system "docker pull #{variant.container.image}"
135
+ end
136
+ end
137
+ end
138
+
101
139
  def report
102
140
  turn_on_stty_opost
103
141
 
104
142
  table = Terminal::Table.new(title: Rainbow("MatrixEval").blue.bright + " Summary", alignment: :center) do |table|
105
143
 
106
- table.add_row(Config.vectors.map(&:key) + ['result'])
144
+ headers = Config.vectors.map(&:key) + ['result']
145
+ table.add_row headers.map { |value| { value: value, alignment: :center } }
107
146
  table.add_separator
108
147
 
109
- matrixeval_results.each do |context, success|
148
+ @matrixeval_results.each do |context, success|
110
149
  success_cell = [success ? Rainbow('Success').green : Rainbow('Failed').red]
111
150
  row = (context.variants.map(&:key) + success_cell).map do |value|
112
151
  { value: value, alignment: :center }
@@ -120,28 +159,30 @@ module Matrixeval
120
159
  puts table
121
160
  end
122
161
 
123
- def parallel
124
- contexts = Context.all
162
+ def parallel(collection)
163
+ @threads = [] unless @threads.empty?
164
+ @matrixeval_results = [] unless @matrixeval_results.empty?
125
165
 
126
- contexts.each_slice(contexts.count / workers_count) do |sub_contexts|
127
- threads << Thread.new do
128
- yield sub_contexts
166
+ collection.each_slice(per_worker_contexts_count) do |sub_collection|
167
+ @threads << Thread.new do
168
+ yield sub_collection
129
169
  end
130
170
  end
131
171
 
132
- threads.each(&:join)
172
+ @threads.each(&:join)
133
173
 
134
- threads.each do |thread|
135
- matrixeval_results += thread[:matrixeval_results]
174
+ @threads.each do |thread|
175
+ @matrixeval_results += (thread[:matrixeval_results] || [])
136
176
  end
137
177
  end
138
178
 
139
- def threads
140
- @threads ||= []
179
+
180
+ def per_worker_contexts_count
181
+ [(contexts.count / workers_count), 1].max
141
182
  end
142
183
 
143
- def matrixeval_results
144
- @matrixeval_results ||= []
184
+ def contexts
185
+ @contexts ||= Context.all
145
186
  end
146
187
 
147
188
  def workers_count
@@ -1,13 +1,52 @@
1
- version: 0.1
1
+ version: 0.2
2
2
  target: ruby
3
3
  parallel_workers: number_of_processors
4
+ # commands:
5
+ # - ps
6
+ # - top
7
+ # - an_additional_command
4
8
  matrix:
5
9
  ruby:
10
+ # mounts:
11
+ # - /a/path/need/to/mount:/a/path/mount/to
6
12
  variants:
7
13
  - key: 2.7
8
- image: ruby:2.7.1
14
+ container:
15
+ image: ruby:2.7.1
9
16
  - key: 3.0
10
- image: ruby:3.0.0
11
17
  default: true
18
+ container:
19
+ image: ruby:3.0.0
12
20
  - key: 3.1
13
- image: ruby:3.1.0
21
+ container:
22
+ image: ruby:3.1.0
23
+ # - key: jruby-9.3
24
+ # container:
25
+ # image: jruby:9.3
26
+ # env:
27
+ # PATH: "/opt/jruby/bin:/app/bin:/bundle/bin:$PATH"
28
+
29
+ # rails:
30
+ # variants:
31
+ # - key: 6.1
32
+ # default: true
33
+ # env:
34
+ # RAILS_VERSION: "~> 6.1.0"
35
+ # - key: 7.0
36
+ # env:
37
+ # RAILS_VERSION: "~> 7.0.0"
38
+ # another:
39
+ # variants:
40
+ # - key: key1
41
+ # default: true
42
+ # env:
43
+ # ENV_KEY: 1
44
+ # - key: key2
45
+ # env:
46
+ # ENV_KEY: 2
47
+
48
+ exclude:
49
+ # - ruby: 3.0
50
+ # rails: 4.2
51
+ # - ruby: jruby-9.3
52
+ # rails: 7.0
@@ -1,3 +1,5 @@
1
+ require_relative "./container"
2
+
1
3
  module Matrixeval
2
4
  module Ruby
3
5
  class Variant
@@ -7,14 +9,14 @@ module Matrixeval
7
9
  end
8
10
  end
9
11
 
10
- attr_reader :key, :image, :env, :vector, :default
12
+ attr_reader :key, :env, :vector, :default, :container
11
13
 
12
14
  def initialize(config = {}, vector)
13
15
  raise Error.new("Variant#key is missing") if config["key"].nil?
14
16
 
15
17
  @vector = vector
16
18
  @key = config["key"].to_s
17
- @image = config["image"]
19
+ @container = Container.new(config["container"])
18
20
  @env = config["env"] || {}
19
21
  @default = config["default"] || false
20
22
  end
@@ -24,7 +26,7 @@ module Matrixeval
24
26
  end
25
27
 
26
28
  def bundle_volume_name
27
- "bundle_#{image.gsub(/[^A-Za-z0-9]/,'_')}"
29
+ "bundle_#{container.image.gsub(/[^A-Za-z0-9]/,'_')}"
28
30
  end
29
31
 
30
32
  def id
@@ -30,7 +30,7 @@ module Matrixeval
30
30
  def default_variant
31
31
  variant = variants.find(&:default?)
32
32
  if variant.nil?
33
- raise Error.new("Please set a default variant for matrix #{vector.key}")
33
+ raise Error.new("Please set a default variant for matrix #{key}")
34
34
  end
35
35
 
36
36
  variant
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Matrixeval
4
4
  module Ruby
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.2"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: matrixeval-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hopper Gee
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-09 00:00:00.000000000 Z
11
+ date: 2022-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rainbow
@@ -64,7 +64,6 @@ files:
64
64
  - CHANGELOG.md
65
65
  - CODE_OF_CONDUCT.md
66
66
  - Gemfile
67
- - Gemfile.lock
68
67
  - LICENSE.txt
69
68
  - README.md
70
69
  - Rakefile
@@ -78,6 +77,7 @@ files:
78
77
  - lib/matrixeval/ruby/command_line/parse_context_arguments.rb
79
78
  - lib/matrixeval/ruby/config.rb
80
79
  - lib/matrixeval/ruby/config/yaml.rb
80
+ - lib/matrixeval/ruby/container.rb
81
81
  - lib/matrixeval/ruby/context.rb
82
82
  - lib/matrixeval/ruby/context/find_by_command_options.rb
83
83
  - lib/matrixeval/ruby/docker_compose.rb
data/Gemfile.lock DELETED
@@ -1,37 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- matrixeval-ruby (0.1.0)
5
- concurrent-ruby
6
- rainbow (~> 3.1)
7
- terminal-table
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- byebug (11.1.3)
13
- concurrent-ruby (1.1.9)
14
- minitest (5.15.0)
15
- minitest-focus (1.3.1)
16
- minitest (>= 4, < 6)
17
- mocha (1.13.0)
18
- rainbow (3.1.1)
19
- rake (13.0.6)
20
- terminal-table (3.0.2)
21
- unicode-display_width (>= 1.1.1, < 3)
22
- unicode-display_width (2.1.0)
23
-
24
- PLATFORMS
25
- x86_64-darwin-19
26
- x86_64-linux
27
-
28
- DEPENDENCIES
29
- byebug
30
- matrixeval-ruby!
31
- minitest (~> 5.0)
32
- minitest-focus
33
- mocha
34
- rake (~> 13.0)
35
-
36
- BUNDLED WITH
37
- 2.2.32