matrixeval 0.1.0 → 0.4.0

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: e2f92ab631d36382a3fe2796928681d6c0a7eddaeea0d74b7165647fa3166c81
4
- data.tar.gz: c45c4f0d82a430846049f07ac2a659ded7cc3cb054512823beea37af09175e1b
3
+ metadata.gz: f340adc04181b907e790e3028bb80f1de0d4ea91f1ec4477087d7b2631bde065
4
+ data.tar.gz: e6845d5bcf308d0974b9241420ef3a1dbc8a3fa544bbad43543cae7f6079203e
5
5
  SHA512:
6
- metadata.gz: c696eaf66bb2daba16dc82221f47a3f0fab5362dc6883c9d72656e690690810491fce0ed2d63b4e30cb4152c0dad940156d9c4754cc2c86d88c4e66acc68f6c9
7
- data.tar.gz: 9476247c48c5028eaac4a2e983e6e11c55d7233a23a01e5618ecd874b3dba5e1da7c1f08f4576af9f7c2f1532e370e271df8366c615582051b7339df73a07d02
6
+ metadata.gz: 9b733e83ca820507963da27358d419154d1023ae60e821121935dc116cc3880123e1c1fb8af5b0355d5f6d854b8e1e0f42c4823408b5308008a3ea2e74fd0e21
7
+ data.tar.gz: af5163f1de81ea41d3882f1930f741a9434dd88c181743820d63d837ed19eacf76651644d85310d276c5ca82ff89094fb88327675a24567caadf7fbcd5ccece0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2022-02-03
3
+ # [0.4.0] - 2022-02-26
4
+
5
+ - Test your code against different versions of dependencies
6
+ - Support 3rd plugin
7
+ # [0.1.0] - 2022-02-09
4
8
 
5
9
  - Initial release
data/Gemfile CHANGED
@@ -8,3 +8,7 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "minitest", "~> 5.0"
11
+
12
+ gem "minitest-focus"
13
+ gem "byebug"
14
+ gem "mocha"
data/README.md CHANGED
@@ -1,9 +1,17 @@
1
- # Matrixeval
1
+ # MatrixEval
2
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`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Test your code against multiple versions of dependencies like:
4
+ - Programming language version
5
+ - Framework version
6
+ - Package version
7
+ - Environment variables
4
8
 
5
- TODO: Delete this and the text above, and describe your gem
9
+ ## Features
6
10
 
11
+ - Parallel test your code against multiple versions of dependencies combinations.
12
+ - Test your code against a specific dependencies combination.
13
+ - Choose any docker image you like for each job.
14
+ - Easy to use CLI to speed up your development efficiency
7
15
  ## Installation
8
16
 
9
17
  Add this line to your application's Gemfile:
@@ -20,9 +28,86 @@ Or install it yourself as:
20
28
 
21
29
  $ gem install matrixeval
22
30
 
31
+ ### Plugins
32
+
33
+ If you plan to test ruby code, you can use [matrixeval-ruby](https://github.com/MatrixEval/matrixeval-ruby) directly.
34
+
23
35
  ## Usage
24
36
 
25
- TODO: Write usage instructions here
37
+ Initialize
38
+
39
+ ```bash
40
+ matrixeval init
41
+ ```
42
+
43
+ Customize `matrixeval.yml` file and run commands like:
44
+
45
+ ```bash
46
+ matrixeval --all COMMAND
47
+ matrixeval --PROGRAMMING_LANGUAGE LANGUAGE_VERSION --PACKAGE_NAME PACKAGE_VERSION COMMAND OPTIONS
48
+ matrixeval bash
49
+ ```
50
+ Run `matrixeval --help` for more details
51
+
52
+ ### Configuration Example
53
+
54
+ Here is the configuration file `matrixeval.yml` which will auto created by `matrixeval init`
55
+
56
+ ```yaml
57
+ version: 0.4
58
+ project_name: REPLACE_ME
59
+ parallel_workers: number_of_processors
60
+ # commands:
61
+ # - ps
62
+ # - top
63
+ # - an_additional_command
64
+ # mounts:
65
+ # - /a/path/need/to/mount:/a/path/mount/to
66
+ matrix:
67
+ # YOUR_PROGRAMMING_LANGUAGE_NAME:
68
+ # main: true
69
+ # variants:
70
+ # - key: LANGUAGE_VERSION_1
71
+ # default: true
72
+ # container:
73
+ # image: LANGUAGE_DOCKER_NAME_1
74
+ # - key: LANGUAGE_VERSION_2
75
+ # container:
76
+ # image: LANGUAGE_DOCKER_NAME_2
77
+ # env:
78
+ # AN_ENV_KEY: ENV_VALUE
79
+ # mounts:
80
+ # - /a/path/need/to/mount:/a/path/mount/to
81
+
82
+ # another:
83
+ # variants:
84
+ # - key: key1
85
+ # default: true
86
+ # env:
87
+ # ENV_KEY: 1
88
+ # - key: key2
89
+ # env:
90
+ # ENV_KEY: 2
91
+
92
+ exclude:
93
+ # - YOUR_PROGRAMMING_LANGUAGE_NAME: LANGUAGE_VERSION_1
94
+ # another: key1
95
+
96
+ docker-compose-extend:
97
+ # services:
98
+ # postgres:
99
+ # image: postgres:12.8
100
+ # volumes:
101
+ # - postgres12:/var/lib/postgresql/data
102
+ # environment:
103
+ # POSTGRES_HOST_AUTH_METHOD: trust
104
+
105
+ # redis:
106
+ # image: redis:6.2-alpine
107
+
108
+ # volumes:
109
+ # postgres12:
110
+ ```
26
111
 
27
112
  ## Development
28
113
 
@@ -32,7 +117,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
117
 
33
118
  ## Contributing
34
119
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/matrixeval. 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/blob/main/CODE_OF_CONDUCT.md).
120
+ Bug reports and pull requests are welcome on GitHub at https://github.com/matrixeval/matrixeval. 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/blob/main/CODE_OF_CONDUCT.md).
36
121
 
37
122
  ## License
38
123
 
@@ -40,4 +125,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
125
 
41
126
  ## Code of Conduct
42
127
 
43
- Everyone interacting in the Matrixeval project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/matrixeval/blob/main/CODE_OF_CONDUCT.md).
128
+ 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/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require "rake/testtask"
6
6
  Rake::TestTask.new(:test) do |t|
7
7
  t.libs << "test"
8
8
  t.libs << "lib"
9
- t.test_files = FileList["test/**/*_test.rb"]
9
+ t.test_files = FileList["test/matrixeval/**/*_test.rb"]
10
10
  end
11
11
 
12
12
  task default: :test
data/bin/test ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ system("ruby -Ilib:test #{ARGV.join(" ")}")
data/exe/matrixeval ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'matrixeval'
4
+
5
+ Matrixeval.start(ARGV)
data/exe/meval ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'matrixeval'
4
+
5
+ Matrixeval.start(ARGV)
@@ -0,0 +1,80 @@
1
+ module Matrixeval
2
+ class CommandLine
3
+ class ParseContextArguments
4
+ class << self
5
+ def call(context_arguments)
6
+ new(context_arguments).call
7
+ end
8
+ end
9
+
10
+ attr_reader :context_arguments, :options
11
+
12
+ def initialize(context_arguments)
13
+ @context_arguments = context_arguments
14
+ @options = {}
15
+ end
16
+
17
+ def call
18
+ parse!
19
+ options
20
+ end
21
+
22
+ private
23
+
24
+ def parse!
25
+ OptionParser.new do |opts|
26
+ opts.version = Config.target.version
27
+ opts.program_name = ""
28
+ opts.banner = <<~USAGE
29
+ Usage:
30
+ matrixeval(meval) [OPTIONS] COMMAND
31
+ USAGE
32
+
33
+ opts.separator ""
34
+ opts.separator "Options:"
35
+
36
+ opts.on "-a", "--all", "# Run the COMMAND against all matrix combinations"
37
+
38
+ Config.vectors.each do |vector|
39
+ # short = "-#{vector.short_key}"
40
+ long = "--#{vector.key} [VERSION]"
41
+ desc = [
42
+ "# Run the COMMAND against a specific #{vector.key} version",
43
+ "# Options: #{vector.variants.map(&:key).join("/")}",
44
+ "# Default: #{vector.default_variant.key}",
45
+ "# Customizable"
46
+ ]
47
+ opts.separator ""
48
+ opts.on(long, *desc)
49
+ end
50
+
51
+ opts.separator ""
52
+ opts.separator "Commands: #{Config.commands.join("/")} (Customizable)"
53
+
54
+ opts.separator ""
55
+ opts.separator "MatrixEval Options:"
56
+
57
+ opts.on("-h", "--help", "# Show help") do
58
+ puts opts.help
59
+ exit
60
+ end
61
+
62
+ opts.on("-v", "--version", "# Show version") do
63
+ puts opts.version
64
+ exit
65
+ end
66
+
67
+ opts.separator ""
68
+ opts.separator "Customizations:"
69
+ opts.separator " You can customize all options in matrixeval.yml"
70
+
71
+ Config.target.cli_example_lines.each do |line|
72
+ opts.separator line
73
+ end
74
+
75
+ end.parse!(context_arguments, into: options)
76
+ end
77
+
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,50 @@
1
+ module Matrixeval
2
+ class CommandLine
3
+ class ParseInitArguments
4
+ class << self
5
+ def call(arguments)
6
+ new(arguments).call
7
+ end
8
+ end
9
+
10
+ attr_reader :init_arguments, :options
11
+
12
+ def initialize(init_arguments)
13
+ @init_arguments = init_arguments
14
+ @options = {}
15
+ end
16
+
17
+ def call
18
+ parse!
19
+ options
20
+ end
21
+
22
+ private
23
+
24
+ def parse!
25
+ OptionParser.new do |opts|
26
+ opts.version = Matrixeval::VERSION
27
+ opts.program_name = ""
28
+ opts.banner = <<~USAGE
29
+ Usage:
30
+ matrixeval(meval) init [Options]
31
+ USAGE
32
+
33
+ opts.separator ""
34
+ opts.separator "Options:"
35
+ opts.on("-t", "--target [TARGET]", *[
36
+ "# Initialize with a specific target",
37
+ "# Options: #{Matrixeval.targets.keys}",
38
+ "# Default: none"
39
+ ])
40
+
41
+ opts.on("-h", "--help", "# Show help") do
42
+ puts opts.help
43
+ exit
44
+ end
45
+ end.parse!(init_arguments, into: options)
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,57 @@
1
+ require_relative "./command_line/parse_context_arguments"
2
+ require_relative "./command_line/parse_init_arguments"
3
+
4
+ module Matrixeval
5
+
6
+ COMMANDS = ['bash', 'dash', 'sh', 'zsh']
7
+
8
+ class CommandLine
9
+
10
+ attr_reader :argv
11
+
12
+ def initialize(argv)
13
+ @argv = argv
14
+ end
15
+
16
+ def valid?
17
+ init? ||
18
+ !context_options.empty? ||
19
+ !seperator_index.nil?
20
+ end
21
+
22
+ def init?
23
+ @argv[0] == 'init'
24
+ end
25
+
26
+ def init_options
27
+ @init_options ||= ParseInitArguments.call(@argv[1..-1])
28
+ end
29
+
30
+ def all?
31
+ context_options[:all]
32
+ end
33
+
34
+ def context_options
35
+ @context_options ||= ParseContextArguments.call(context_arguments)
36
+ end
37
+
38
+ def context_arguments
39
+ arguments = @argv[0...seperator_index]
40
+ arguments << "-h" if @argv.empty?
41
+ arguments
42
+ end
43
+
44
+ def rest_arguments
45
+ @argv[seperator_index..-1]
46
+ end
47
+
48
+ private
49
+
50
+ def seperator_index
51
+ @argv.index do |argument|
52
+ Config.commands.include?(argument)
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,47 @@
1
+ require 'yaml'
2
+
3
+ module Matrixeval
4
+ class Config
5
+ class YAML
6
+
7
+ class MissingError < StandardError; end
8
+
9
+ class << self
10
+
11
+ def create_for(target_name)
12
+ return if File.exist?(path)
13
+
14
+ FileUtils.cp(
15
+ target(target_name).matrixeval_yml_template_path,
16
+ path
17
+ )
18
+ end
19
+
20
+ def path
21
+ Matrixeval.working_dir.join("matrixeval.yml")
22
+ end
23
+
24
+ def [](key)
25
+ yaml[key]
26
+ end
27
+
28
+ def yaml
29
+ raise MissingError unless File.exist?(path)
30
+
31
+ ::YAML.load File.read(path)
32
+ end
33
+
34
+ private
35
+
36
+ def target(target_name)
37
+ target_klass(target_name).new
38
+ end
39
+
40
+ def target_klass(target_name)
41
+ Matrixeval.targets[target_name] || Target
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,101 @@
1
+ require 'yaml'
2
+ require_relative "./config/yaml"
3
+
4
+ module Matrixeval
5
+ class Config
6
+ class << self
7
+
8
+ def version
9
+ YAML["version"]
10
+ end
11
+
12
+ def target_name
13
+ YAML["target"]
14
+ end
15
+
16
+ def target
17
+ @target ||= target_klass.new
18
+ end
19
+
20
+ def project_name
21
+ name = YAML["project_name"]
22
+
23
+ if name.nil? || name.strip.empty?
24
+ raise Error.new('missing project_name')
25
+ end
26
+
27
+ name
28
+ end
29
+
30
+ def vectors
31
+ @vectors = YAML["matrix"].map do |key, vector_config|
32
+ Vector.new(key, vector_config)
33
+ end
34
+ end
35
+
36
+ def main_vector
37
+ vectors.find(&:main?)
38
+ end
39
+
40
+ def rest_vectors
41
+ vectors.reject(&:main?)
42
+ end
43
+
44
+ def variant_combinations
45
+ main_vector_variants.product(*rest_vector_variants_matrix)
46
+ end
47
+
48
+ def main_vector_variants
49
+ main_vector.variants
50
+ end
51
+
52
+ def rest_vector_variants_matrix
53
+ rest_vectors.map(&:variants)
54
+ end
55
+
56
+ def exclusions
57
+ YAML["exclude"] || []
58
+ end
59
+
60
+ def parallel_workers
61
+ YAML["parallel_workers"] || "number_of_processors"
62
+ end
63
+
64
+ def commands
65
+ cmds = YAML["commands"] || []
66
+ COMMANDS + target.support_commands + cmds
67
+ end
68
+
69
+ def docker_compose_extend_raw
70
+ DockerCompose::ExtendRaw.new(
71
+ YAML["docker-compose-extend"] || {}
72
+ )
73
+ end
74
+
75
+ def env
76
+ YAML["env"] || {}
77
+ end
78
+
79
+ def mounts
80
+ YAML["mounts"] || []
81
+ end
82
+
83
+ def all_mounts
84
+ mounts + all_variant_mounts
85
+ end
86
+
87
+ private
88
+
89
+ def all_variant_mounts
90
+ Config.vectors
91
+ .map(&:variants).flatten
92
+ .map(&:mounts).flatten
93
+ end
94
+
95
+ def target_klass
96
+ Matrixeval.targets[target_name&.to_sym] || Target
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,13 @@
1
+ module Matrixeval
2
+ class Container
3
+
4
+ attr_reader :image, :env
5
+
6
+ def initialize(options)
7
+ options ||= {}
8
+ @image = options["image"]
9
+ @env = options["env"] || {}
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ require 'erb'
2
+ require 'json'
3
+
4
+ module Matrixeval
5
+ class Context
6
+ class BuildDockerComposeExtend
7
+ class << self
8
+ def call(context)
9
+ new(context).call
10
+ end
11
+ end
12
+
13
+ attr_reader :context
14
+
15
+ def initialize(context)
16
+ @context = context
17
+ end
18
+
19
+ def matrix_combination_id
20
+ context.id
21
+ end
22
+
23
+ def call
24
+ DockerCompose::Extend.new(docker_compose_extend)
25
+ end
26
+
27
+ private
28
+
29
+ def docker_compose_extend
30
+ JSON.parse(render_erb)
31
+ end
32
+
33
+ def render_erb
34
+ ERB.new(
35
+ Config.docker_compose_extend_raw.content
36
+ ).result(binding)
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,65 @@
1
+ module Matrixeval
2
+ class Context
3
+ class FindByCommandOptions
4
+ class << self
5
+ def call(options)
6
+ new(options).call
7
+ end
8
+ end
9
+
10
+ attr_reader :options
11
+
12
+ def initialize(options)
13
+ @options = options
14
+ end
15
+
16
+ def call
17
+ context = Context.all.find do |context|
18
+ context.main_variant == main_variant &&
19
+ context.rest_variants == rest_variants
20
+ end
21
+
22
+ raise Error.new("Can't find a corresponding matrix") if context.nil?
23
+
24
+ context
25
+ end
26
+
27
+ private
28
+
29
+ def main_variant
30
+ dig_variant Config.main_vector
31
+ end
32
+
33
+ def rest_variants
34
+ Config.rest_vectors.map do |vector|
35
+ dig_variant vector
36
+ end.sort do |v1, v2|
37
+ v1.id <=> v2.id
38
+ end
39
+ end
40
+
41
+ def dig_variant(vector)
42
+ if option_key?(vector.key)
43
+ find_variant(vector)
44
+ else
45
+ vector.default_variant
46
+ end
47
+ end
48
+
49
+ def find_variant(vector)
50
+ vector.variants.find do |variant|
51
+ option(vector.key) == variant.key
52
+ end
53
+ end
54
+
55
+ def option(key)
56
+ options[key.to_sym] || options[key.to_s]
57
+ end
58
+
59
+ def option_key?(key)
60
+ options.key?(key.to_sym) || options.key?(key.to_s)
61
+ end
62
+
63
+ end
64
+ end
65
+ end