matrixeval-ruby 0.1.0 → 0.2.2

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: 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